diff options
author | Anton Gorenkov | 2011-07-06 06:12:45 +0000 |
---|---|---|
committer | Marc-Andre Laperle | 2011-07-06 06:34:49 +0000 |
commit | 3b6f6642b801502b9c6125aec81bcc82213014c6 (patch) | |
tree | 9c7489c6f4fee8f2d21abd6e5a5cccf19638fff6 | |
parent | 82a3d0c2809615e92303ce430ada5f5840ef9333 (diff) | |
download | org.eclipse.cdt-3b6f6642b801502b9c6125aec81bcc82213014c6.tar.gz org.eclipse.cdt-3b6f6642b801502b9c6125aec81bcc82213014c6.tar.xz org.eclipse.cdt-3b6f6642b801502b9c6125aec81bcc82213014c6.zip |
Bug 339795 - [checker] Checker that finds class members that are not
initialized in constructor
7 files changed, 727 insertions, 3 deletions
diff --git a/codan/org.eclipse.cdt.codan.checkers/OSGI-INF/l10n/bundle.properties b/codan/org.eclipse.cdt.codan.checkers/OSGI-INF/l10n/bundle.properties index a59ba9ebebb..3d003daed30 100644 --- a/codan/org.eclipse.cdt.codan.checkers/OSGI-INF/l10n/bundle.properties +++ b/codan/org.eclipse.cdt.codan.checkers/OSGI-INF/l10n/bundle.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2010 Alena Laskavaia and others. +# Copyright (c) 2010, 2011 Alena Laskavaia and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at @@ -111,6 +111,10 @@ checker.name.AbstractClassCreation = Abstract class cannot be instantiated problem.name.AbstractClassCreation = Abstract class cannot be instantiated problem.messagePattern.AbstractClassCreation = The type ''{0}'' must implement the inherited pure virtual method ''{1}'' problem.description.AbstractClassCreation = All inherited pure virtual methods must be implemented to allow instantiation of the class +checker.name.ClassMembersInitialization = Class members should be properly initialized +problem.name.ClassMembersInitialization = Class members should be properly initialized +problem.messagePattern.ClassMembersInitialization = Member ''{0}'' was not initialized in this constructor +problem.description.ClassMembersInitialization = Class members should be properly initialized to avoid random behavior checker.name.UnusedSymbolInFileScopeChecker = Unused symbols and declarations in file scope problem.description.UnusedVariableDeclarationProblem = Finds unused global variable declarations in file scope diff --git a/codan/org.eclipse.cdt.codan.checkers/plugin.xml b/codan/org.eclipse.cdt.codan.checkers/plugin.xml index b8e6b7f9150..0f3f1c76678 100644 --- a/codan/org.eclipse.cdt.codan.checkers/plugin.xml +++ b/codan/org.eclipse.cdt.codan.checkers/plugin.xml @@ -384,5 +384,19 @@ name="%problem.name.UnusedStaticFunctionProblem"> </problem> </checker> + <checker + class="org.eclipse.cdt.codan.internal.checkers.ClassMembersInitializationChecker" + id="org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization" + name="%checker.name.ClassMembersInitialization"> + <problem + category="org.eclipse.cdt.codan.core.categories.ProgrammingProblems" + defaultEnabled="true" + defaultSeverity="Warning" + description="%problem.description.ClassMembersInitialization" + id="org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization" + messagePattern="%problem.messagePattern.ClassMembersInitialization" + name="%problem.name.ClassMembersInitialization"> + </problem> + </checker> </extension> </plugin> diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.java index ee770a93c81..8a4ad7e6877 100644 --- a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.java +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009,2010 Alena Laskavaia + * Copyright (c) 2009, 2011 Alena Laskavaia * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -20,6 +20,7 @@ public class CheckersMessages extends NLS { public static String CaseBreakChecker_EmptyCaseDescription; public static String CaseBreakChecker_LastCaseDescription; public static String CatchByReference_ReportForUnknownType; + public static String ClassMembersInitializationChecker_SkipConstructorsWithFCalls; public static String NamingConventionFunctionChecker_LabelNamePattern; public static String NamingConventionFunctionChecker_ParameterMethods; public static String ReturnChecker_Param0; diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.properties b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.properties index 2aefeb03335..b219b977cff 100644 --- a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.properties +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2010 Alena Laskavaia and others. +# Copyright (c) 2010, 2011 Alena Laskavaia and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at @@ -11,6 +11,7 @@ CaseBreakChecker_DefaultNoBreakCommentDescription=Comment text to suppress the problem (regular expression): CaseBreakChecker_EmptyCaseDescription=Check also empty case statement (except if last) CaseBreakChecker_LastCaseDescription=Check also the last case statement +ClassMembersInitializationChecker_SkipConstructorsWithFCalls=Skip constructors with initialization function calls CatchByReference_ReportForUnknownType=Report a problem if type cannot be resolved NamingConventionFunctionChecker_LabelNamePattern=Name Pattern NamingConventionFunctionChecker_ParameterMethods=Also check C++ method names diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java new file mode 100644 index 00000000000..c0d16049b3c --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java @@ -0,0 +1,222 @@ +/******************************************************************************* + * Copyright (c) 2011 Anton Gorenkov + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Anton Gorenkov - initial implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.checkers; + +import java.util.Stack; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker; +import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy; +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; +import org.eclipse.cdt.core.dom.ast.IASTIdExpression; +import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IBasicType; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.ICompositeType; +import org.eclipse.cdt.core.dom.ast.IEnumeration; +import org.eclipse.cdt.core.dom.ast.IField; +import org.eclipse.cdt.core.dom.ast.IPointerType; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.ITypedef; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVariableReadWriteFlags; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMName; + +/** + * Checks that class members of simple types (int, float, pointers, + * enumeration types, ...) are properly initialized in constructor. + * Not initialized members may cause to unstable or random behavior + * of methods that are working with their value. + * + * @author Anton Gorenkov + * + */ +public class ClassMembersInitializationChecker extends AbstractIndexAstChecker { + public static final String ER_ID = "org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization"; //$NON-NLS-1$ + public static final String PARAM_SKIP = "skip"; //$NON-NLS-1$ + + public void processAst(IASTTranslationUnit ast) { + ast.accept(new OnEachClass()); + } + + class OnEachClass extends ASTVisitor { + + // NOTE: Classes can be nested and even can be declared in constructors of the other classes + private Stack< Set<IField> > constructorsStack = new Stack< Set<IField> >(); + + OnEachClass() { + shouldVisitDeclarations = true; + shouldVisitNames = true; + shouldVisitExpressions = skipConstructorsWithFCalls(); + } + + public int visit(IASTDeclaration declaration) { + ICPPConstructor constructor = getConstructor(declaration); + if (constructor != null) { + Set<IField> fieldsInConstructor = constructorsStack.push(new HashSet<IField>()); + + // Add all class fields + for (IField field : constructor.getClassOwner().getDeclaredFields()) { + if (isSimpleType(field.getType()) && !field.isStatic()) { + fieldsInConstructor.add(field); + } + } + } + return PROCESS_CONTINUE; + } + + public int leave(IASTDeclaration declaration) { + if (getConstructor(declaration) != null) { + for (IField field : constructorsStack.pop()) { + reportProblem(ER_ID, declaration, field.getName()); + } + } + return PROCESS_CONTINUE; + } + + public int visit(IASTExpression expression) { + if (!constructorsStack.empty() && expression instanceof IASTFunctionCallExpression) { + Set<IField> actualContructorFields = constructorsStack.peek(); + if (!actualContructorFields.isEmpty()) { + boolean skipCurrentConstructor = false; + IASTFunctionCallExpression fCall = (IASTFunctionCallExpression)expression; + IASTExpression fNameExp = fCall.getFunctionNameExpression(); + if (fNameExp instanceof IASTIdExpression) { + IASTIdExpression fName = (IASTIdExpression)fNameExp; + IBinding fBinding = fName.getName().resolveBinding(); + if (fBinding instanceof ICPPMethod) { + ICPPMethod method = (ICPPMethod)fBinding; + ICompositeType constructorOwner = actualContructorFields.iterator().next().getCompositeTypeOwner(); + if (constructorOwner == method.getClassOwner() && !method.getType().isConst()) { + skipCurrentConstructor = true; + } + } else if (fBinding instanceof ICPPFunction) { + for (IASTInitializerClause argument : fCall.getArguments()) { + if (referencesThis(argument)) { + skipCurrentConstructor = true; + break; + } + } + } + } + if (skipCurrentConstructor) { + constructorsStack.peek().clear(); + } + } + } + return PROCESS_CONTINUE; + } + + /** Checks whether expression references this (directly, by pointer or by reference) + * + */ + public boolean referencesThis(IASTNode expr) { + if (expr instanceof IASTLiteralExpression) { + IASTLiteralExpression litArg = (IASTLiteralExpression)expr; + if (litArg.getKind() == IASTLiteralExpression.lk_this) { + return true; + } + } else if (expr instanceof ICPPASTUnaryExpression) { + ICPPASTUnaryExpression unExpr = (ICPPASTUnaryExpression)expr; + switch (unExpr.getOperator()) { + case ICPPASTUnaryExpression.op_amper: + case ICPPASTUnaryExpression.op_star: + case ICPPASTUnaryExpression.op_bracketedPrimary: + return referencesThis(unExpr.getOperand()); + } + } + return false; + } + + public int visit(IASTName name) { + if (!constructorsStack.empty()) { + Set<IField> actualContructorFields = constructorsStack.peek(); + if (!actualContructorFields.isEmpty()) { + IBinding binding = name.resolveBinding(); + if (actualContructorFields.contains(binding)) { + if ((CPPVariableReadWriteFlags.getReadWriteFlags(name) & PDOMName.WRITE_ACCESS) != 0) { + actualContructorFields.remove(binding); + } + } + } + } + return PROCESS_CONTINUE; + } + + /** Checks whether class member of the specified type should be initialized + * + * @param type Type to check + * @return true if type is: + * - basic type (int, float, ...) + * - pointer + * - enum + * - reference (should be initialized in initialization list) + * - typedef to the another native type. + * + * @note: Not supported types (but maybe should be): + * - array + * - union + * - unknown type (need user preference?) + * - template parameter (need user preference?) + */ + private boolean isSimpleType(IType type) { + return (type instanceof IBasicType || + type instanceof IPointerType || + type instanceof IEnumeration || + type instanceof ICPPReferenceType || + (type instanceof ITypedef && isSimpleType( ((ITypedef)type).getType()) ) ); + } + + /** Checks that specified declaration is a class constructor + * (it is a class member and its name is equal to class name) + */ + private ICPPConstructor getConstructor(IASTDeclaration decl) { + if (decl instanceof ICPPASTFunctionDefinition) { + ICPPASTFunctionDefinition functionDefinition = (ICPPASTFunctionDefinition)decl; + IBinding binding = functionDefinition.getDeclarator().getName().resolveBinding(); + if (binding instanceof ICPPConstructor) { + ICPPConstructor constructor = (ICPPConstructor) binding; + if (constructor.getClassOwner().getKey()!=ICPPClassType.k_union) { + return constructor; + } + } + } + + return null; + } + + } + + @Override + public void initPreferences(IProblemWorkingCopy problem) { + super.initPreferences(problem); + addPreference(problem, PARAM_SKIP, CheckersMessages.ClassMembersInitializationChecker_SkipConstructorsWithFCalls, Boolean.TRUE); + } + + public boolean skipConstructorsWithFCalls() { + return (Boolean) getPreference(getProblemById(ER_ID, getFile()), PARAM_SKIP); + } + +} diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ClassMembersInitializationCheckerTest.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ClassMembersInitializationCheckerTest.java new file mode 100644 index 00000000000..a0b261b1db6 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ClassMembersInitializationCheckerTest.java @@ -0,0 +1,480 @@ +/******************************************************************************* + * Copyright (c) 2011 Anton Gorenkov + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Anton Gorenkov - initial implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.internal.checkers; + +import org.eclipse.cdt.codan.core.test.CheckerTestCase; +import org.eclipse.cdt.codan.internal.checkers.ClassMembersInitializationChecker; + +/** + * Test for {@see ClassMembersInitializationChecker} class + * + */ +public class ClassMembersInitializationCheckerTest extends CheckerTestCase { + @Override + public boolean isCpp() { + return true; + } + + @Override + public void setUp() throws Exception { + super.setUp(); + enableProblems(ClassMembersInitializationChecker.ER_ID); + } + + private void disableSkipConstructorsWithFCalls() { + setPreferenceValue(ClassMembersInitializationChecker.ER_ID, ClassMembersInitializationChecker.PARAM_SKIP, false); + } + + public void checkMultiErrorsOnLine(int line, int count) { + for (int i = 0; i < count; ++i) { + checkErrorLine(line); + } + assertEquals(count, markers.length); + } + + // class C { + // int m; + // C() : m(0) {} // No warnings. + // }; + public void testInitializationListShouldBeChecked() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // class C { + // int m; + // C() { m = 0; } // No warnings. + // }; + public void testAssignmentsInContructorShouldBeChecked() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // class C { + // int m; + // unsigned int ui; + // float f; + // double d; + // bool b; + // char c; + // long l; + // C() {} // 7 warnings for: m, ui, f, d, b, c, l. + // }; + public void testBasicTypesShouldBeInitialized() { + loadCodeAndRun(getAboveComment()); + checkMultiErrorsOnLine(9, 7); + } + + // class Value {}; + // class C { + // int* i; + // Value* v; + // C() {} // 2 warnings for: i, v. + // } + public void testPointersShouldBeInitialized() { + loadCodeAndRun(getAboveComment()); + checkMultiErrorsOnLine(5, 2); + } + + // class Value {}; + // class C { + // int& i; + // Value& v; + // C() {} // 2 warnings for: i, v. + // } + public void testReferencesShouldBeInitialized() { + loadCodeAndRun(getAboveComment()); + checkMultiErrorsOnLine(5, 2); + } + + // enum Enum { v1, v2 }; + // class C { + // Enum e; + // C() {} // 1 warning for: e. + // } + public void testEnumsShouldBeInitialized() { + loadCodeAndRun(getAboveComment()); + checkMultiErrorsOnLine(4, 1); + } + + // enum Enum { v1, v2 }; + // class Value {}; + // typedef int IntTypedef; + // typedef int* IntPtrTypedef; + // typedef int& IntRefTypedef; + // typedef Enum EnumTypedef; + // typedef Value ValueTypedef; + // class C { + // IntTypedef i; + // IntPtrTypedef ip; + // IntRefTypedef ir; + // EnumTypedef e; + // ValueTypedef v; + // C() {} // 5 warnings for: i, ip, ir, e. + // } + public void testTypedefsShouldBeInitialized() { + loadCodeAndRun(getAboveComment()); + checkMultiErrorsOnLine(14, 4); + } + + // class C { + // C() : i1(0) {} // 1 warning for: i2. + // C(int) : i2(0) {} // 1 warning for: i1. + // int i1, i2; + // }; + public void testAFewConstructorsHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(2, 3); + } + + // template <typename T1, typename T2> + // class C { + // C() : i1(0), t1(T1()) {} // 1 warning for: i2. + // int i1, i2; + // T1 t1; + // T2 t2; + // }; + public void testTemplateClassHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(3); + } + + // class C { + // template <typename T> + // C() : i1(0) {} // 1 warning for: i2. + // int i1, i2; + // }; + public void testTemplateConstructorHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(3); + } + + // class C { + // C(); // No warnings. + // int i; + // }; + public void testTemplateConstructorDeclarationOnlyHandling() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // class C { + // C(); + // int i1, i2; + // }; + // C::C() : i1(0) {} // 1 warning for: i2. + public void testExternalContructorHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(5); + } + + // template <typename T1, typename T2> + // class C { + // C(); + // int i1, i2; + // T1 t1; + // T2 t2; + // }; + // C::C() : i1(0), t1(T1()) {} // 1 warning for: i2. + public void testExternalContructorOfTemplateClassHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(8); + } + + // class C { + // template <typename T> + // C(); + // int i1, i2; + // }; + // template <typename T> + // C::C() : i1(0) {} // 1 warning for: i2. + public void testExternalTemplateContructorHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(7); + } + + // template <typename T1, typename T2> + // class C { + // template <typename T> + // C(); + // int i1, i2; + // T1 t1; + // T2 t2; + // }; + // template <typename T1, typename T2> + // template <typename T> + // C<T1,T2>::C() : i1(0), t1(T1()) {} // 1 warning for: i2. + public void testExternalTemplateContructorOfTemplateClassHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(11); + } + + // class C { + // class NestedC { + // NestedC() : i(0) {} // No warnings. + // int i; + // }; + // C() {} // 1 warning for: i. + // int i; + // }; + public void testNestedClassesHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(6); + } + + // class C { + // C() // 1 warning for: i. + // { + // class NestedC { + // NestedC() { i = 0; } // No warnings. + // int i; + // }; + // } + // int i; + // }; + public void testNestedClassInConstructorHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(2); + } + + // class C { + // C(); + // int i; + // }; + // + // C::C() // 1 warning for: i. + // { + // class NestedC { // No warnings. + // NestedC() { i = 0; } + // int i; + // }; + // } + public void testNestedClassInExternalConstructorHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(6); + } + + // class C { + // C() // 1 warning for: i. + // { + // class NestedC { + // NestedC() { i = 0; } // No warnings. + // void C() { i = 0; } // No warnings. + // int i; + // }; + // } + // int i; + // }; + public void testNestedClassWithMethodNamedAsAnotherClassHandling() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(2); + } + + // class C { + // C() {} // 1 warning for: i. + // int someFunction() { i = 0; } // No warnings. + // int i; + // }; + public void testAssignmentIsNotInConstructor() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(2); + } + + // class CBase { + // CBase() : i1(0) {} // No warnings. + // int i1; + // }; + // class CDerived : public CBase { + // CDerived() : i2(0) {} // No warnings. + // int i2; + // }; + public void testBaseClassMemberShouldNotBeTakenIntoAccount() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // class C { + // C() {} // No warnings. + // static int i1, i2; + // }; + // int C::i1 = 0; + // // NOTE: Static members are always initialized with 0, so there should not be warning on C::i2 + // int C::i2; + public void testNoErrorsOnStaticMembers() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // void func(int & a) { a = 0; } + // class C { + // C() { func(i); } // No warnings. + // int i; + // }; + public void testNoErrorsOnFunctionCallInitialization() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // void func(const int & a) {} + // class C { + // C() { func(i); } // 1 warning for: i. + // int i; + // }; + public void testNoErrorsOnReadingFunctionCall() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(3); + } + + // class C { + // C() { (i1) = 0; *&i2 = 0; } // No warnings. + // int i1, i2; + // }; + public void testNoErrorsOnComplexAssignment() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // class C { + // C() : i1(0) { // No warnings. + // i2 = i1; + // int someVar = 0; + // i3 = someVar; + // } + // int i1, i2, i3; + // }; + public void testNoErrorsOnChainInitialization() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // class A { protected: A(){} public: int a; }; // 1 warning for: a. + // class C: public A { + // C() { + // a = 1; + // } + // }; + public void testErrorOnProtectedConstructor() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(1); + } + + // struct S { + // int i; + // S() {} // 1 warning for: i. + // }; + public void testCheckStructs() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(3); + } + + // union U { + // int a; + // char b; + // U() { // No warnings. + // a=0; + // } + // }; + public void testSkipUnions() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // class C { + // int c; + // }; + public void testNoErrorsIfThereIsNoConstructorsDefined() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // class C { + // int i; + // C(bool b) { // No warnings. + // if (b) + // i = 0; + // // else - 'i' will be not initialized + // } + // }; + public void testNoErrorsIfMemberWasInitializedInOneOfTheIfBranch() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // class A { + // int a; + // A(int a) { setA(a); } // No warnings. + // A() { getA(); } // 1 warning for: a. + // void setA(int a) { + // this->a = a; + // } + // int getA() const { + // return a; + // } + // }; + public void testUsingMethodsInConstructorWithPreference() { + loadCodeAndRun(getAboveComment()); + checkErrorLines(4); + } + + // class A; + // void initializeA1(A*); + // void initializeA2(A**); + // void initializeA3(A&); + // + // class A { + // int a; + // A() { initializeA1(this); } // No warnings. + // A(int a) { initializeA2(&this); } // No warnings. + // A(float a) { initializeA3(*this); } // No warnings. + // A(double a) { initializeA3(*(this)); } // No warnings. + // }; + public void testUsingConstMethodsInConstructorWithPreference() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + + // class A { + // int a; + // A(int a) { setA(a); } // 1 warning for: a. + // A() { getA(); } // 1 warning for: a. + // void setA(int a) { + // this->a = a; + // } + // int getA() const { + // return a; + // } + // }; + public void testUsingMethodsInConstructorWithoutPreference() { + disableSkipConstructorsWithFCalls(); + loadCodeAndRun(getAboveComment()); + checkErrorLines(3,4); + } + + // class A; + // void initializeA1(A*); + // void initializeA2(A**); + // void initializeA3(A&); + // + // class A { + // int a; + // A() { initializeA1(this); } // 1 warning for: a. + // A(int a) { initializeA2(&this); } // 1 warning for: a. + // A(float a) { initializeA3(*this); } // 1 warning for: a. + // A(double a) { initializeA3(*(this)); } // 1 warning for: a. + // }; + public void testUsingConstMethodsInConstructorWithoutPreference() { + disableSkipConstructorsWithFCalls(); + loadCodeAndRun(getAboveComment()); + checkErrorLines(8,9,10,11); + } + +} diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/AutomatedIntegrationSuite.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/AutomatedIntegrationSuite.java index 7958a4b8d17..b70376f252f 100644 --- a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/AutomatedIntegrationSuite.java +++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/AutomatedIntegrationSuite.java @@ -20,6 +20,7 @@ import org.eclipse.cdt.codan.core.internal.checkers.AssignmentInConditionChecker import org.eclipse.cdt.codan.core.internal.checkers.AssignmentToItselfCheckerTest; import org.eclipse.cdt.codan.core.internal.checkers.CaseBreakCheckerTest; import org.eclipse.cdt.codan.core.internal.checkers.CatchByReferenceTest; +import org.eclipse.cdt.codan.core.internal.checkers.ClassMembersInitializationCheckerTest; import org.eclipse.cdt.codan.core.internal.checkers.FormatStringCheckerTest; import org.eclipse.cdt.codan.core.internal.checkers.NonVirtualDestructorCheckerTest; import org.eclipse.cdt.codan.core.internal.checkers.ProblemBindingCheckerTest; @@ -56,6 +57,7 @@ public class AutomatedIntegrationSuite extends TestSuite { suite.addTestSuite(AssignmentToItselfCheckerTest.class); suite.addTestSuite(CaseBreakCheckerTest.class); suite.addTestSuite(CatchByReferenceTest.class); + suite.addTestSuite(ClassMembersInitializationCheckerTest.class); suite.addTestSuite(FormatStringCheckerTest.class); suite.addTestSuite(NonVirtualDestructorCheckerTest.class); suite.addTestSuite(ProblemBindingCheckerTest.class); |