mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-04 14:55:41 +02:00
bug 343429: [checker] Checker to pinpoint unused static functions in a file
A few false positives corrected
This commit is contained in:
parent
5efd41bb09
commit
91ab5f5876
2 changed files with 93 additions and 13 deletions
|
@ -12,8 +12,10 @@ package org.eclipse.cdt.codan.internal.checkers;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import org.eclipse.cdt.codan.checkers.CodanCheckersActivator;
|
import org.eclipse.cdt.codan.checkers.CodanCheckersActivator;
|
||||||
import org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker;
|
import org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker;
|
||||||
|
@ -36,9 +38,11 @@ import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
import org.eclipse.cdt.core.dom.ast.IFunction;
|
import org.eclipse.cdt.core.dom.ast.IFunction;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
|
||||||
import org.eclipse.cdt.core.dom.ast.IProblemType;
|
import org.eclipse.cdt.core.dom.ast.IProblemType;
|
||||||
import org.eclipse.cdt.core.dom.ast.IType;
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
|
@ -134,22 +138,33 @@ public class UnusedSymbolInFileScopeChecker extends AbstractIndexAstChecker {
|
||||||
}
|
}
|
||||||
} else if (binding instanceof IVariable) {
|
} else if (binding instanceof IVariable) {
|
||||||
if (storageClass == IASTDeclSpecifier.sc_extern) {
|
if (storageClass == IASTDeclSpecifier.sc_extern) {
|
||||||
|
IASTInitializer initializer = decl.getInitializer();
|
||||||
|
// initializer makes "extern" declaration to become definition do not count these
|
||||||
|
if (initializer==null) {
|
||||||
externVariableDeclarations.put(binding, decl);
|
externVariableDeclarations.put(binding, decl);
|
||||||
|
}
|
||||||
} else if (storageClass == IASTDeclSpecifier.sc_static) {
|
} else if (storageClass == IASTDeclSpecifier.sc_static) {
|
||||||
IType type = ((IVariable) binding).getType();
|
IType type = ((IVariable) binding).getType();
|
||||||
// account for class constructor and avoid possible false positive
|
// account for class constructor and avoid possible false positive
|
||||||
if (!(type instanceof ICPPClassType) && !(type instanceof IProblemType)) {
|
if (!(type instanceof ICPPClassType) && !(type instanceof IProblemType)) {
|
||||||
|
// check if initializer disqualifies it
|
||||||
IASTInitializer initializer = decl.getInitializer();
|
IASTInitializer initializer = decl.getInitializer();
|
||||||
|
IASTInitializerClause clause = null;
|
||||||
if (initializer instanceof IASTEqualsInitializer) {
|
if (initializer instanceof IASTEqualsInitializer) {
|
||||||
IASTEqualsInitializer equalsInitializer = (IASTEqualsInitializer) initializer;
|
IASTEqualsInitializer equalsInitializer = (IASTEqualsInitializer) initializer;
|
||||||
IASTInitializerClause clause = equalsInitializer.getInitializerClause();
|
clause = equalsInitializer.getInitializerClause();
|
||||||
|
} else if (initializer instanceof ICPPASTConstructorInitializer) {
|
||||||
|
ICPPASTConstructorInitializer constructorInitializer = (ICPPASTConstructorInitializer) initializer;
|
||||||
|
IASTInitializerClause[] args = constructorInitializer.getArguments();
|
||||||
|
if (args.length==1)
|
||||||
|
clause = args[0];
|
||||||
|
}
|
||||||
if (clause instanceof IASTLiteralExpression) {
|
if (clause instanceof IASTLiteralExpression) {
|
||||||
IASTLiteralExpression literalExpression = (IASTLiteralExpression) clause;
|
IASTLiteralExpression literalExpression = (IASTLiteralExpression) clause;
|
||||||
String literal = literalExpression.toString();
|
String literal = literalExpression.toString();
|
||||||
if (isFilteredOut(literal, unusedVariableProblem, PARAM_EXCEPT_ARG_LIST))
|
if (isFilteredOut(literal, unusedVariableProblem, PARAM_EXCEPT_ARG_LIST))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
staticVariableDeclarations.put(binding, decl);
|
staticVariableDeclarations.put(binding, decl);
|
||||||
}
|
}
|
||||||
|
@ -200,6 +215,16 @@ public class UnusedSymbolInFileScopeChecker extends AbstractIndexAstChecker {
|
||||||
if (binding instanceof ICPPMethod)
|
if (binding instanceof ICPPMethod)
|
||||||
return PROCESS_CONTINUE;
|
return PROCESS_CONTINUE;
|
||||||
|
|
||||||
|
if (binding instanceof IProblemBinding) {
|
||||||
|
// avoid false positives related to unresolved names
|
||||||
|
String plainName = name.toString();
|
||||||
|
filterOutByPlainName(externFunctionDeclarations, plainName);
|
||||||
|
filterOutByPlainName(staticFunctionDeclarations, plainName);
|
||||||
|
filterOutByPlainName(staticFunctionDefinitions, plainName);
|
||||||
|
filterOutByPlainName(externVariableDeclarations, plainName);
|
||||||
|
filterOutByPlainName(staticVariableDeclarations, plainName);
|
||||||
|
}
|
||||||
|
|
||||||
IASTNode parentNode = name.getParent();
|
IASTNode parentNode = name.getParent();
|
||||||
|
|
||||||
if (!(parentNode instanceof IASTFunctionDefinition || parentNode instanceof IASTFunctionDeclarator)) {
|
if (!(parentNode instanceof IASTFunctionDefinition || parentNode instanceof IASTFunctionDeclarator)) {
|
||||||
|
@ -218,6 +243,17 @@ public class UnusedSymbolInFileScopeChecker extends AbstractIndexAstChecker {
|
||||||
return PROCESS_CONTINUE;
|
return PROCESS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void filterOutByPlainName(Map<IBinding, IASTDeclarator> declarators, String id) {
|
||||||
|
Iterator<Entry<IBinding, IASTDeclarator>> iter = declarators.entrySet().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Entry<IBinding, IASTDeclarator> entry = iter.next();
|
||||||
|
IASTDeclarator decl = entry.getValue();
|
||||||
|
IASTName astName = getAstName(decl);
|
||||||
|
if (id.equals(astName.toString()))
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
CodanCheckersActivator.log(e);
|
CodanCheckersActivator.log(e);
|
||||||
|
|
|
@ -161,6 +161,29 @@ public class UnusedSymbolInFileScopeCheckerTest extends CheckerTestCase {
|
||||||
checkErrorLine(1);
|
checkErrorLine(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static int test_fun(int i) {}
|
||||||
|
// int i = test_fun(X);
|
||||||
|
public void testStaticFunction_Definition_UnknownParameterType() throws IOException {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static void test_fun(void) {}
|
||||||
|
// void Class::fun() {
|
||||||
|
// test_fun();
|
||||||
|
// }
|
||||||
|
public void testStaticFunction_Definition_InQualifiedFunction() throws IOException {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static int test_fun(X) {}
|
||||||
|
// int i = test_fun(X);
|
||||||
|
public void testStaticFunction_Definition_UnknownArgumentType() throws IOException {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Extern variables declaration
|
// Extern variables declaration
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -194,6 +217,12 @@ public class UnusedSymbolInFileScopeCheckerTest extends CheckerTestCase {
|
||||||
|
|
||||||
// int test_var;
|
// int test_var;
|
||||||
// int test_var2=0;
|
// int test_var2=0;
|
||||||
|
public void testGlobalVariable_Definition() throws IOException {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// extern int test_var=0; // not quite legal but some compilers allow that
|
||||||
public void testExternVariable_Definition() throws IOException {
|
public void testExternVariable_Definition() throws IOException {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkNoErrors();
|
checkNoErrors();
|
||||||
|
@ -231,6 +260,15 @@ public class UnusedSymbolInFileScopeCheckerTest extends CheckerTestCase {
|
||||||
checkNoErrors();
|
checkNoErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static int test_var;
|
||||||
|
// void Class::fun() {
|
||||||
|
// test_var = 0;
|
||||||
|
// }
|
||||||
|
public void testStaticVariable_Used_InQualifiedFunction() throws IOException {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
// class Class;
|
// class Class;
|
||||||
// static Class test_var; // constructor is called here
|
// static Class test_var; // constructor is called here
|
||||||
public void testStaticVariable_Used_Constructor() throws IOException {
|
public void testStaticVariable_Used_Constructor() throws IOException {
|
||||||
|
@ -244,16 +282,22 @@ public class UnusedSymbolInFileScopeCheckerTest extends CheckerTestCase {
|
||||||
checkNoErrors();
|
checkNoErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
// static char* test_var="$Id: file.c,v 1.1 2000/01/01 11:11:11 agvozdev Exp $";
|
// static char* test_var="$Id: UnusedSymbolInFileScopeCheckerTest.java,v 1.2 2011/04/29 11:17:42 agvozdev Exp $";
|
||||||
public void testExternVariable_Declaration_cvs_ident() throws IOException {
|
public void testExternVariable_Declaration_CvsIdent() throws IOException {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkNoErrors();
|
checkNoErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
// static char* test_var="@(#) $Header: /src/file.c,v 1.1 2000/01/01 11:11:11 agvozdev Exp $";
|
// static char* test_var="@(#) $Header: /cvsroot/tools/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/UnusedSymbolInFileScopeCheckerTest.java,v 1.2 2011/04/29 11:17:42 agvozdev Exp $";
|
||||||
public void testExternVariable_Declaration_sccs_ident() throws IOException {
|
public void testExternVariable_Declaration_SccsIdent() throws IOException {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkNoErrors();
|
checkNoErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static char test_var[]("@(#) $Id: UnusedSymbolInFileScopeCheckerTest.java,v 1.2 2011/04/29 11:17:42 agvozdev Exp $");
|
||||||
|
public void testExternVariable_Declaration_CvsIdentInitializer() throws IOException {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue