com.simiacryptus.ref.ops.InsertFreeRefs Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of refcount-autocoder Show documentation
Show all versions of refcount-autocoder Show documentation
Java 8 Reference Counting Code Utilities
The newest version!
/*
* Copyright (c) 2020 by Andrew Charneski.
*
* The author licenses this file to you under the
* Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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.simiacryptus.ref.ops;
import com.simiacryptus.ref.core.ASTUtil;
import com.simiacryptus.ref.core.ProjectInfo;
import com.simiacryptus.ref.lang.RefAware;
import com.simiacryptus.ref.lang.RefIgnore;
import com.simiacryptus.ref.lang.RefUtil;
import org.eclipse.jdt.core.dom.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@RefIgnore
public class InsertFreeRefs extends RefASTOperator {
protected InsertFreeRefs(ProjectInfo projectInfo, @Nonnull CompilationUnit compilationUnit, @Nonnull File file) {
super(projectInfo, compilationUnit, file);
}
private static int firstLine(@Nonnull Block body, int declaredAt) {
final List statements = body.statements();
for (int i = Math.max(declaredAt, 0); i < statements.size(); i++) {
final Statement statement = statements.get(i);
if (statement instanceof ConstructorInvocation) {
declaredAt = i;
break;
}
if (statement instanceof SuperConstructorInvocation) {
declaredAt = i;
break;
}
}
return declaredAt;
}
public void addFreeRef(@Nonnull VariableDeclaration declaration, @Nonnull ITypeBinding typeBinding) {
if (skip(declaration)) return;
debug(1, declaration, "addFreeRef: %s", declaration);
if (isRefCounted(declaration, typeBinding)) {
final SimpleName name = declaration.getName();
ASTNode parent = declaration.getParent();
boolean isNonNull = ASTUtil.hasAnnotation(declaration.resolveBinding(), Nonnull.class);
if (parent instanceof MethodDeclaration) {
final MethodDeclaration node = (MethodDeclaration) parent;
final Block body = node.getBody();
if (null != body) insertFreeRefs(typeBinding, name, body, -1, isNonNull);
} else if (parent instanceof LambdaExpression) {
final LambdaExpression lambdaExpression = (LambdaExpression) parent;
final ASTNode body = lambdaExpression.getBody();
if (body instanceof Block) {
insertFreeRefs(typeBinding, name, (Block) body, -1, isNonNull);
} else {
final Block block = ast.newBlock();
lambdaExpression.setBody(block);
final IMethodBinding methodBinding = resolveMethodBinding(lambdaExpression);
if (hasReturnValue(lambdaExpression, lambdaExpression.getParent(), methodBinding)) {
final ReturnStatement returnStatement = ast.newReturnStatement();
returnStatement.setExpression(copyIfAttached((Expression) body));
block.statements().add(returnStatement);
} else {
block.statements().add(ast.newExpressionStatement(copyIfAttached((Expression) body)));
}
debug(lambdaExpression, "Replace lambda %s with block %s", lambdaExpression, block);
insertFreeRefs(typeBinding, name, block, -1, isNonNull);
}
} else if (parent instanceof VariableDeclarationStatement) {
final ASTNode parentParent = parent.getParent();
if (parentParent instanceof Block) {
final Block parentBlock = (Block) parentParent;
insertFreeRefs(typeBinding, name, parentBlock, parentBlock.statements().indexOf(parent), isNonNull);
} else {
warn(declaration, "Cannot add freeRef for %s (VariableDeclarationStatement) in %s : %s", name, parentParent.getClass(), parentParent.toString().trim());
}
} else if (parent instanceof FieldDeclaration) {
if (!Modifier.isStatic(((FieldDeclaration) parent).getModifiers())) {
add_freeRef_entry(declaration, typeBinding, name, parent);
}
} else {
warn(declaration, "Cannot add freeRef for %s in %s : %s",
name,
parent.getClass(), parent.toString().trim());
}
} else {
debug(declaration, "%s is not refcounted (%s)", declaration, typeBinding);
}
}
public void add_freeRef_entry(@Nonnull VariableDeclaration declaration, @Nonnull ITypeBinding typeBinding, @Nonnull SimpleName name, @Nonnull ASTNode parent) {
final ASTNode fieldParent = parent.getParent();
if (fieldParent instanceof TypeDeclaration) {
final TypeDeclaration typeDeclaration = (TypeDeclaration) fieldParent;
final Optional freeMethodOpt = ASTUtil.findMethod(typeDeclaration, "_free");
if (freeMethodOpt.isPresent()) {
debug(declaration, "Adding freeRef for %s to (%s)", name, getLocation(name));
final boolean isFinal = isFinal(declaration);
final List statements = RefUtil.get(freeMethodOpt).getBody().statements();
if (!isFinal) {
statements.add(0, ast.newExpressionStatement(setToNull(name)));
}
statements.add(0, isFinal && ASTUtil.hasAnnotation(declaration.resolveBinding(), Nonnull.class) ? newFreeRef(name, typeBinding) : freeRefStatement(name, typeBinding));
} else {
fatal(declaration, "Cannot add freeRef for %s::%s - no _free method", typeDeclaration.getName(), declaration.getName());
}
} else {
fatal(declaration, "Cannot add freeRef for %s (FieldDeclaration) in %s : %s", name, fieldParent.getClass(), fieldParent.toString().trim());
}
}
public void insertFreeRef(@Nonnull ITypeBinding typeBinding, @Nonnull SimpleName node, @Nonnull Block body, int line, boolean isNonNull) {
final Statement statement = isNonNull ? newFreeRef(node, typeBinding) : freeRefStatement(node, typeBinding);
if (line < 0) {
body.statements().add(0, statement);
} else {
body.statements().add(line + 1, statement);
}
debug(1, body, "Added freeRef for value %s (%s) at line %s", node, typeBinding.getQualifiedName(), line);
}
public void insertFreeRefs(@Nonnull ITypeBinding typeBinding, @Nonnull SimpleName node, @Nonnull Block body, int declaredAt, boolean isNonNull) {
debug(1, node, "Insert freeRef for %s", node);
declaredAt = firstLine(body, declaredAt);
final StatementOfInterest lastMention = lastMention(body, node, declaredAt);
if (null == lastMention) {
debug(node, "No mentions in body. Adding freeRef");
insertFreeRef(typeBinding, node, body, declaredAt, isNonNull);
} else {
final List inScopeExits = exits(body, declaredAt, lastMention.line);
if (lastMention.isComplexReturn()) {
insertFreeRef_ComplexReturn(typeBinding, node, lastMention.block, lastMention.line, isNonNull);
} else if (lastMention.isReturn()) {
debug(node, "Last usage returns reference to %s", node);
} else {
//final boolean canFlowPast = lastMention.line == mainBodySize - 1 && inScopeExits.stream().anyMatch(x -> x.isReturnValue());
if (!canFlowPast(body, lastMention.line)) {
debug(node, "Last reference to %s at %s past all exits", node, lastMention.line);
} else {
debug(node, "Adding freeRef for %s after last reference at %s", node, lastMention.line);
insertFreeRef(typeBinding, node, lastMention.block, lastMention.line, isNonNull);
}
}
for (StatementOfInterest exitPoint : inScopeExits) {
if (lastMention.block == exitPoint.block) continue;
if (exitPoint.isReturn()) {
final ReturnStatement returnStatement = (ReturnStatement) exitPoint.statement;
final Expression expression = returnStatement.getExpression();
if (null != expression) {
if (expression.toString().equals(node.toString())) {
debug(node, "Last usage returns reference");
} else if (null != ASTUtil.findExpressions(returnStatement, (ASTNode) node).stream().findAny().orElse(null)) {
debug(node, "Last usage uses reference");
insertFreeRef_ComplexReturn(typeBinding, node, exitPoint.block, exitPoint.line, isNonNull);
} else {
debug(node, "Exit %s unrelated to %s at line %s", returnStatement, node, exitPoint.line);
insertFreeRef(typeBinding, node, exitPoint.block, exitPoint.line - 1, isNonNull);
}
} else {
debug(node, "Empty return");
insertFreeRef(typeBinding, node, exitPoint.block, exitPoint.line - 1, isNonNull);
}
} else {
final ThrowStatement throwStatement = (ThrowStatement) exitPoint.statement;
final Expression expression = throwStatement.getExpression();
if (null != expression) {
if (expression.toString().equals(node.toString())) {
debug(node, "Last usage throws reference");
} else if (null != ASTUtil.findExpressions(throwStatement, (ASTNode) node).stream().findAny().orElse(null)) {
debug(node, "Last usage (throws) uses reference");
insertFreeRef_ComplexThrow(typeBinding, node, exitPoint.block, exitPoint.line, isNonNull);
} else {
debug(node, "Throw %s unrelated to %s at line %s", throwStatement, node, exitPoint.line);
insertFreeRef(typeBinding, node, exitPoint.block, exitPoint.line - 1, isNonNull);
}
} else {
debug(node, "Empty return");
insertFreeRef(typeBinding, node, exitPoint.block, exitPoint.line - 1, isNonNull);
}
}
}
}
}
protected boolean isFinal(@Nonnull VariableDeclaration declaration) {
if (declaration instanceof SingleVariableDeclaration) {
return Modifier.isFinal(((SingleVariableDeclaration) declaration).getModifiers());
} else {
final ASTNode declarationParent = declaration.getParent();
if (declarationParent instanceof VariableDeclarationExpression) {
return Modifier.isFinal(((VariableDeclarationExpression) declarationParent).getModifiers());
} else if (declarationParent instanceof VariableDeclarationStatement) {
return Modifier.isFinal(((VariableDeclarationStatement) declarationParent).getModifiers());
} else if (declarationParent instanceof FieldDeclaration) {
return Modifier.isFinal(((FieldDeclaration) declarationParent).getModifiers());
} else {
throw new RuntimeException(declarationParent.getClass().getName());
}
}
}
protected void freeExpressionResult(@Nonnull Expression node, @Nonnull ITypeBinding typeBinding) {
if (isRefCounted(node, typeBinding)) {
debug(node, "Ref-returning method: %s", node);
final ASTNode parent = node.getParent();
if (parent instanceof MethodInvocation) {
final MethodInvocation methodInvocation = (MethodInvocation) parent;
final IMethodBinding methodBinding = resolveMethodBinding(methodInvocation);
if (null == methodBinding) {
warn(methodInvocation, "Unresolved Binding: %s", methodInvocation);
return;
}
if (0 <= methodInvocation.arguments().indexOf(node)) {
if (ASTUtil.hasAnnotation(methodBinding.getDeclaringClass(), RefAware.class)) {
debug(node, "Ref is consumed as parameter to method: %s", node);
return;
} else {
debug(node, "Ref is consumed by non-RefAware method: %s", node);
}
}
final Expression expression = methodInvocation.getExpression();
if (null != expression && null != ASTUtil.findExpressions(expression, (ASTNode) node).stream().findAny().orElse(null)) {
if (!methodConsumesSelfRefs(methodBinding)) {
debug(node, "Adding freeref for Ref-returning method: %s", node);
freeRefs(node, typeBinding, false);
} else {
debug(node, "Chained method consumes ref for Ref-returning method: %s", node);
}
return;
}
debug(node, "Result consumed by method");
} else if (parent instanceof FieldAccess) {
final FieldAccess methodInvocation = (FieldAccess) parent;
final IVariableBinding fieldBinding = resolveFieldBinding(methodInvocation);
if (null == fieldBinding) {
warn(methodInvocation, "Unresolved Binding: %s", methodInvocation);
}
if (null != ASTUtil.findExpressions(methodInvocation.getExpression(), (ASTNode) node).stream().findAny().orElse(null)) {
freeRefs(node, typeBinding, false);
} else {
debug(node, "Result consumed by method");
}
} else if (parent instanceof ExpressionStatement) {
final ASTNode statementParent = parent.getParent();
if (statementParent instanceof Block) {
final Block block = (Block) statementParent;
final int lineNumber = block.statements().indexOf(parent);
block.statements().set(lineNumber, freeRefUtilStatement(node, typeBinding));
debug(node, "Wrapped method call with freeref at line " + lineNumber);
} else {
warn(node, "Non-block method call statement: %s (%s)", parent.getClass(), parent);
}
} else if (parent instanceof InfixExpression) {
freeRefs(node, typeBinding, false);
//addFreeRef(parent, node, typeBinding);
debug(node, "Reftype wrapped as local variable: %s (%s)", parent.getClass(), parent);
} else if (parent instanceof ReturnStatement) {
debug(node, "Reftype returned from method: %s", parent);
} else if (parent instanceof VariableDeclarationFragment) {
debug(node, "Reftype assigned as local variable: %s", parent);
} else if (null == parent) {
warn(node, "Null parent: %s", node);
} else {
warn(node, "Non-ExpressionStatement method: %s (%s)", parent.getClass(), parent);
}
} else {
warn(node, "Ignored method returning %s: %s", typeBinding.getQualifiedName(), node);
}
}
protected boolean canFlowPast(@Nonnull Block body, int line) {
final List statements = body.statements();
if (statements.size() - 1 > line) return true;
return !isTerminal((Statement) statements.get(line));
}
protected void freeRefs(@Nonnull Expression node, @Nonnull ITypeBinding typeBinding, boolean isNonNull) {
final LambdaExpression lambda = ASTUtil.getLambda(node);
if (null != lambda) {
toBlock(lambda);
}
Statement statement = ASTUtil.getStatement(node);
if (null == statement) {
warn(node, "No containing statement for %s", node);
return;
}
final ASTNode statementParent = statement.getParent();
if (!(statementParent instanceof Block)) {
Block block = ast.newBlock();
replace(statement, block);
block.statements().add(statement);
debug(node, "Wrapped %s in new block", node);
freeRefs(node, typeBinding, isNonNull);
return;
}
Block block = (Block) statementParent;
if (statement instanceof ReturnStatement) {
final Expression expression = ((ReturnStatement) statement).getExpression();
final String identifier = getTempIdentifier(node);
final ITypeBinding returnTypeBinding = resolveTypeBinding(expression);
if (null == returnTypeBinding) {
warn(expression, "Unresolved binding for %s", expression);
return;
}
final Type type = getType(expression, returnTypeBinding, true);
assert type != null;
final VariableDeclarationStatement localVariable = newLocalVariable(identifier, expression, type);
replace(expression, ast.newSimpleName(identifier));
final List statements = block.statements();
final int lineNumber = statements.indexOf(statement);
statements.add(lineNumber, localVariable);
debug(node, "Wrapped %s in new variable %s", node, identifier);
freeRefs(ASTUtil.findExpressions(((VariableDeclarationFragment) localVariable.fragments().get(0)).getInitializer(), node).stream().findAny().orElse(null), typeBinding, isNonNull);
return;
}
final Type type = getType(node, typeBinding, true);
if (type == null) {
warn(node, "Cannot declare type %s", typeBinding);
return;
}
final String identifier = getTempIdentifier(node);
replace(node, ast.newSimpleName(identifier));
assert node.getParent() == null;
final List statements = block.statements();
final int lineNumber = statements.indexOf(statement);
final SimpleName name = ast.newSimpleName(identifier);
statements.add(lineNumber + 1, isNonNull ? newFreeRef(name, typeBinding) : freeRefStatement(name, typeBinding));
statements.add(lineNumber, newLocalVariable(identifier, node, type));
debug(node, "Wrapped method call with freeRef for %s at line %s", name, lineNumber);
}
@Nullable
protected Type getType(@Nonnull Expression node, @Nonnull ITypeBinding typeBinding, boolean isDeclaration) {
final Type type = getType(node, typeBinding.getQualifiedName(), isDeclaration);
if (null == type) {
final ITypeBinding superclass = typeBinding.getSuperclass();
if (null != superclass) {
return getType(node, superclass, isDeclaration);
}
}
return type;
}
protected boolean hasBreak(Statement statement) {
if (statement instanceof BreakStatement) {
return true;
} else if (statement instanceof IfStatement) {
final IfStatement ifStatement = (IfStatement) statement;
final Statement thenStatement = ifStatement.getThenStatement();
if (thenStatement != null && hasBreak(thenStatement)) return true;
final Statement elseStatement = ifStatement.getElseStatement();
if (elseStatement != null && hasBreak(elseStatement)) return true;
return false;
} else if (statement instanceof TryStatement) {
final TryStatement tryStatement = (TryStatement) statement;
final Block statementFinally = tryStatement.getFinally();
if (null != statementFinally && hasBreak(statementFinally)) return true;
final Block body = tryStatement.getBody();
if (null != body && hasBreak(body)) return true;
for (CatchClause catchStatement : (List) tryStatement.catchClauses()) {
if (hasBreak(catchStatement.getBody())) return true;
}
return false;
} else if (statement instanceof Block) {
final Block block = (Block) statement;
return ((List) block.statements()).stream().anyMatch(x -> hasBreak(x));
} else if (statement instanceof SynchronizedStatement) {
return hasBreak(((SynchronizedStatement) statement).getBody());
} else {
return false;
}
}
protected boolean hasReturnValue(LambdaExpression node, ASTNode lambdaParent, @Nullable IMethodBinding methodBinding) {
if (null != methodBinding) {
if (methodBinding.getReturnType().toString().equals("void")) {
return false;
} else {
return true;
}
} else {
if (!(lambdaParent instanceof MethodInvocation)) {
debug(lambdaParent, "lambda %s has no return value", lambdaParent);
return false;
}
return this.hasReturnValue((MethodInvocation) lambdaParent, node);
}
}
protected void insertFreeRef_ComplexReturn(@Nonnull ITypeBinding typeBinding, @Nonnull SimpleName node, @Nonnull Block block, int line, boolean isNonNull) {
debug(1, node, "Adding freeRef for %s at %s", node, line);
ReturnStatement returnStatement = (ReturnStatement) block.statements().get(line);
final String identifier = getTempIdentifier(node);
final List statements = block.statements();
final Expression expression = returnStatement.getExpression();
final VariableDeclarationStatement newLocalVariable = newLocalVariable(identifier, expression);
if (null == newLocalVariable) {
warn(node, "Cannot define local variable for %s", expression);
final TryStatement tryStatement = ast.newTryStatement();
replace(returnStatement, tryStatement);
tryStatement.getBody().statements().add(returnStatement);
tryStatement.setFinally(ast.newBlock());
tryStatement.getFinally().statements().add(isNonNull ? newFreeRef(node, typeBinding) : freeRefStatement(node, typeBinding));
debug(node, "Added freeRef in finally for %s", node);
} else {
statements.add(line, isNonNull ? newFreeRef(copyIfAttached(node), typeBinding) : freeRefStatement(copyIfAttached(node), typeBinding));
statements.add(line, newLocalVariable);
returnStatement.setExpression(ast.newSimpleName(identifier));
debug(node, "Added freeRef for return value %s using %s at %s", node, newLocalVariable, line);
}
}
@SuppressWarnings("unused")
protected void insertFreeRef_ComplexThrow(@Nonnull ITypeBinding typeBinding, @Nonnull SimpleName node, @Nonnull Block block, int line, boolean isNonNull) {
ThrowStatement throwStatement = (ThrowStatement) block.statements().get(line);
final String identifier = getTempIdentifier(block);
final List statements = block.statements();
final Expression expression = throwStatement.getExpression();
final VariableDeclarationStatement newLocalVariable = newLocalVariable(identifier, expression);
if (null == newLocalVariable) {
warn(block, "Cannot define local variable for %s", expression);
final TryStatement tryStatement = ast.newTryStatement();
replace(throwStatement, tryStatement);
tryStatement.getBody().statements().add(throwStatement);
tryStatement.setFinally(ast.newBlock());
tryStatement.getFinally().statements().add(freeRefStatement(node, typeBinding));
debug(block, "Added freeRef in finally for %s", node);
} else {
statements.add(line, freeRefStatement(copyIfAttached(node), typeBinding));
statements.add(line, newLocalVariable);
throwStatement.setExpression(ast.newSimpleName(identifier));
debug(block, "Added freeRef for throw value %s", node);
}
}
protected boolean isTerminal(Statement statement) {
if (statement instanceof ReturnStatement) return true;
else if (statement instanceof ThrowStatement) return true;
else if (statement instanceof IfStatement) {
final IfStatement ifStatement = (IfStatement) statement;
final Statement thenStatement = ifStatement.getThenStatement();
if (thenStatement != null) {
final Statement elseStatement = ifStatement.getElseStatement();
if (elseStatement != null) {
if (isTerminal(thenStatement) && isTerminal(elseStatement)) {
return true;
}
}
}
return false;
} else if (statement instanceof TryStatement) {
final TryStatement tryStatement = (TryStatement) statement;
final Block statementFinally = tryStatement.getFinally();
if (null != statementFinally && isTerminal(statementFinally)) return true;
final Block body = tryStatement.getBody();
if (null != body && !isTerminal(body)) return false;
for (CatchClause catchStatement : (List) tryStatement.catchClauses()) {
if (!isTerminal(catchStatement.getBody())) return false;
}
return true;
} else if (statement instanceof Block) {
final Block block = (Block) statement;
final List statements = block.statements();
if (statements.size() == 0) return false;
return isTerminal((Statement) statements.get(statements.size() - 1));
} else if (statement instanceof SynchronizedStatement) {
return isTerminal(((SynchronizedStatement) statement).getBody());
}
if (statement instanceof WhileStatement) {
final WhileStatement whileStatement = (WhileStatement) statement;
if (!whileStatement.getExpression().toString().equals("true")) return false;
return !hasBreak(whileStatement.getBody());
} else {
return false;
}
}
@Nonnull
private Assignment setToNull(@Nonnull SimpleName name) {
final Assignment assignment = ast.newAssignment();
assignment.setLeftHandSide(copyIfAttached(name));
assignment.setOperator(Assignment.Operator.ASSIGN);
assignment.setRightHandSide(ast.newNullLiteral());
return assignment;
}
@RefIgnore
public static class ModifyVariableDeclarationFragment extends InsertFreeRefs {
public ModifyVariableDeclarationFragment(ProjectInfo projectInfo, @Nonnull CompilationUnit compilationUnit, @Nonnull File file) {
super(projectInfo, compilationUnit, file);
}
@Override
public void endVisit(@Nonnull VariableDeclarationFragment declaration) {
if (skip(declaration)) return;
debug(declaration, "VariableDeclarationFragment: %s", declaration);
final ASTNode parent = declaration.getParent();
final ITypeBinding declarationType = getTypeBinding(declaration);
if (null == declarationType) {
warn(declaration, "Cannot resolve type of %s", declaration);
return;
}
if (parent instanceof VariableDeclarationStatement) {
final ITypeBinding typeBinding = resolveBinding(((VariableDeclarationStatement) parent).getType());
if (null == typeBinding) {
warn(declaration, "Cannot resolve type of %s", parent);
return;
}
addFreeRef(declaration, declarationType);
} else if (parent instanceof VariableDeclarationExpression) {
final Type type = ((VariableDeclarationExpression) parent).getType();
final ITypeBinding typeBinding = resolveBinding(type);
if (null == typeBinding) {
warn(declaration, "Cannot resolve type of %s", parent);
return;
}
addFreeRef(declaration, declarationType);
} else if (parent instanceof FieldDeclaration) {
final ITypeBinding typeBinding = resolveBinding(((FieldDeclaration) parent).getType());
if (null == typeBinding) {
warn(declaration, "Cannot resolve type of %s", parent);
return;
}
addFreeRef(declaration, declarationType);
} else if (parent instanceof LambdaExpression) {
final LambdaExpression lambdaExpression = (LambdaExpression) parent;
final IMethodBinding methodBinding = resolveMethodBinding(lambdaExpression);
if (methodBinding == null) {
warn(declaration, "Cannot resolve method of %s", parent);
return;
}
addFreeRef(declaration, declarationType);
} else {
warn(declaration, "Cannot handle %s", parent);
}
}
}
@RefIgnore
public static class ModifySingleVariableDeclaration extends InsertFreeRefs {
public ModifySingleVariableDeclaration(ProjectInfo projectInfo, @Nonnull CompilationUnit compilationUnit, @Nonnull File file) {
super(projectInfo, compilationUnit, file);
}
@Override
public void endVisit(@Nonnull SingleVariableDeclaration declaration) {
if (skip(declaration)) return;
debug(declaration, "SingleVariableDeclaration: %s", declaration);
final IVariableBinding variableBinding = resolveBinding(declaration);
if (null == variableBinding) {
warn(declaration, "Cannot add freeRef for field access %s (binding not resolved)", declaration.getName());
} else {
addFreeRef(declaration, getTypeBinding(declaration));
}
}
}
@RefIgnore
public static class ModifyClassInstanceCreation extends InsertFreeRefs {
public ModifyClassInstanceCreation(ProjectInfo projectInfo, @Nonnull CompilationUnit compilationUnit, @Nonnull File file) {
super(projectInfo, compilationUnit, file);
}
@Override
public void endVisit(@Nonnull ClassInstanceCreation node) {
debug(node, "Processing constructor: %s", node);
if (skip(node)) {
debug(node, "Skip");
return;
}
final IMethodBinding methodBinding = resolveConstructorBinding(node);
if (null == methodBinding) {
warn(node, "Unresolved constructor binding on %s", node);
return;
}
freeExpressionResult(node, methodBinding.getDeclaringClass());
}
}
@RefIgnore
public static class ModifyMethodInvocation extends InsertFreeRefs {
public ModifyMethodInvocation(ProjectInfo projectInfo, @Nonnull CompilationUnit compilationUnit, @Nonnull File file) {
super(projectInfo, compilationUnit, file);
}
@Override
public void endVisit(@Nonnull MethodInvocation node) {
if (skip(node)) return;
//astRewrite.track(node);
if (Arrays.asList("addRef", "addRef").contains(node.getName().toString())) return;
final IMethodBinding methodBinding = resolveMethodBinding(node);
if (null == methodBinding) {
warn(node, "Unresolved binding on %s", node);
return;
}
freeExpressionResult(node, methodBinding.getReturnType());
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy