/* * Copyright (c) 2014, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.java2dart.engine; import com.google.dart.engine.ast.ArgumentList; import com.google.dart.engine.ast.AssignmentExpression; import com.google.dart.engine.ast.AstNode; import com.google.dart.engine.ast.Block; import com.google.dart.engine.ast.CatchClause; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.ast.Expression; import com.google.dart.engine.ast.Identifier; import com.google.dart.engine.ast.InstanceCreationExpression; import com.google.dart.engine.ast.MethodDeclaration; import com.google.dart.engine.ast.SimpleFormalParameter; import com.google.dart.engine.ast.SimpleIdentifier; import com.google.dart.engine.ast.ThrowExpression; import com.google.dart.engine.ast.TypeArgumentList; import com.google.dart.engine.ast.TypeName; import com.google.dart.engine.ast.VariableDeclarationList; import com.google.dart.engine.ast.visitor.RecursiveAstVisitor; import com.google.dart.engine.context.AnalysisException; import com.google.dart.engine.scanner.Keyword; import com.google.dart.java2dart.Context; import com.google.dart.java2dart.processor.SemanticProcessor; import com.google.dart.java2dart.util.JavaUtils; import static com.google.dart.java2dart.util.AstFactory.identifier; import static com.google.dart.java2dart.util.AstFactory.instanceCreationExpression; import static com.google.dart.java2dart.util.AstFactory.nullLiteral; import static com.google.dart.java2dart.util.AstFactory.string; import static com.google.dart.java2dart.util.AstFactory.typeName; import org.eclipse.jdt.core.dom.ITypeBinding; import java.util.List; /** * Rewrites {@link AnalysisException} creation to gather stack traces. */ public class EngineExceptionProcessor extends SemanticProcessor { public EngineExceptionProcessor(Context context) { super(context); } @Override public void process(CompilationUnit unit) { unit.accept(new RecursiveAstVisitor<Void>() { @Override public Void visitInstanceCreationExpression(InstanceCreationExpression node) { List<Expression> arguments = node.getArgumentList().getArguments(); Identifier typeName = node.getConstructorName().getType().getName(); if (typeName.getName().equals("AnalysisException")) { // "log(new AnalysisException(m))" -> "log(new CaughtException(new AnalysisException(m)))" if (arguments.size() <= 1) { AstNode parent = node.getParent(); if (!(parent instanceof ThrowExpression)) { replaceNode( parent, node, instanceCreationExpression( Keyword.NEW, typeName("CaughtException"), node, nullLiteral())); } return null; } // "new AnalysisException(m, e)" -> "new AnalysisException(m, new CaughtException(e, stack))" if (arguments.size() == 2) { Expression stackTraceNode = nullLiteral(); { Block block = node.getAncestor(Block.class); if (block.getParent() instanceof CatchClause) { CatchClause catchClause = (CatchClause) block.getParent(); SimpleIdentifier stackTraceIdentifier = identifier("stackTrace"); catchClause.setStackTraceParameter(stackTraceIdentifier); stackTraceNode = stackTraceIdentifier; } } arguments.set( 1, instanceCreationExpression( Keyword.NEW, typeName("CaughtException"), arguments.get(1), stackTraceNode)); } } return super.visitInstanceCreationExpression(node); } @Override public Void visitSimpleIdentifier(SimpleIdentifier node) { ITypeBinding typeBinding = context.getNodeTypeBinding(node); if (JavaUtils.isTypeNamed(typeBinding, "com.google.dart.engine.context.AnalysisException")) { AstNode parent = node.getParent(); if (parent instanceof ArgumentList || parent instanceof AssignmentExpression && ((AssignmentExpression) parent).getRightHandSide() == node) { Block block = node.getAncestor(Block.class); if (block != null && block.getParent() instanceof CatchClause) { CatchClause catchClause = (CatchClause) block.getParent(); SimpleIdentifier stackTraceIdentifier = identifier("stackTrace"); catchClause.setStackTraceParameter(stackTraceIdentifier); replaceNode( parent, node, instanceCreationExpression( Keyword.NEW, typeName("CaughtException"), node, stackTraceIdentifier)); } } } return super.visitSimpleIdentifier(node); } @Override public Void visitThrowExpression(ThrowExpression node) { super.visitThrowExpression(node); // "throw thrownException;" in AnalysisContextImpl -> "throw new AnalysisContext(thrownException)" Expression expression = node.getExpression(); if (expression instanceof SimpleIdentifier && ((SimpleIdentifier) expression).getName().equals("thrownException")) { node.setExpression(instanceCreationExpression( Keyword.NEW, typeName("AnalysisException"), string("<rethrow>"), expression)); } return null; } @Override public Void visitTypeName(TypeName node) { // AnalysisException -> CaughtException AstNode parent = node.getParent(); if (parent instanceof VariableDeclarationList || parent instanceof MethodDeclaration || parent instanceof SimpleFormalParameter || parent instanceof TypeArgumentList) { if (node.getName() instanceof SimpleIdentifier) { SimpleIdentifier nameNode = (SimpleIdentifier) node.getName(); if (nameNode.getName().equals("AnalysisException")) { replaceNode(nameNode, identifier("CaughtException")); } } } // done return super.visitTypeName(node); } }); } }