Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergey Prigogin2012-03-14 00:37:27 +0000
committerSergey Prigogin2012-03-14 00:55:38 +0000
commit0f4f703be222407956acec285388fd0fd5c369b3 (patch)
tree3ea50e3daea6c7b8d0df18f2e31eeb23515738b5
parent723ed9f9128d127c36e60f1c4e8c7d122494f342 (diff)
downloadorg.eclipse.cdt-0f4f703be222407956acec285388fd0fd5c369b3.tar.gz
org.eclipse.cdt-0f4f703be222407956acec285388fd0fd5c369b3.tar.xz
org.eclipse.cdt-0f4f703be222407956acec285388fd0fd5c369b3.zip
Determination of output parameters for extracting function from
inside conditional statements and loops.
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java3
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionRefactoringTest.java620
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/BlockFlowInfo.java20
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/BranchFlowInfo.java27
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ConditionalFlowInfo.java44
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/DoWhileFlowInfo.java36
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowAnalyzer.java1012
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowContext.java136
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowInfo.java428
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ForFlowInfo.java45
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FunctionCallFlowInfo.java31
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/GenericConditionalFlowInfo.java35
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/GenericSequentialFlowInfo.java33
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/IfFlowInfo.java39
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/InOutFlowAnalyzer.java143
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/InputFlowAnalyzer.java304
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/LocalFlowInfo.java46
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/LocalVariableIndex.java72
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/RangeBasedForFlowInfo.java36
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ReturnFlowInfo.java40
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/Selection.java164
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/SwitchFlowInfo.java42
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ThrowFlowInfo.java28
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/TryFlowInfo.java41
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/WhileFlowInfo.java32
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/util/ASTNodes.java39
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NameInformation.java25
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NodeContainer.java33
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/StatementExtractor.java3
29 files changed, 3281 insertions, 276 deletions
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
index 29e21800a75..2e4f6fcc360 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
@@ -259,7 +259,8 @@ public class DeclarationWriter extends NodeWriter {
private void writeFunctionDefinition(IASTFunctionDefinition funcDef) {
IASTDeclSpecifier declSpecifier = funcDef.getDeclSpecifier();
- declSpecifier.accept(visitor);
+ if (declSpecifier != null)
+ declSpecifier.accept(visitor);
if (declSpecifier instanceof IASTSimpleDeclSpecifier) {
IASTSimpleDeclSpecifier simDeclSpec = (IASTSimpleDeclSpecifier) declSpecifier;
if (simDeclSpec.getType() != IASTSimpleDeclSpecifier.t_unspecified) {
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionRefactoringTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionRefactoringTest.java
index 159654b32e7..e7d2716525f 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionRefactoringTest.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionRefactoringTest.java
@@ -1,5 +1,4 @@
/*******************************************************************************
- * Copyright (c) 2008, 2012 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -178,19 +177,23 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int A::help() {
// return 42;
//}
- public void testExtractedVariableDefinition() throws Exception {
+ public void testLocalVariableDeclaration_1() throws Exception {
assertRefactoringSuccess();
}
+
//A.h
//#ifndef A_H_
//#define A_H_
//
+ //#include "B.h"
+ //
//class A {
//public:
// A();
// virtual ~A();
- // int foo();
+ // void foo();
+ // B b;
//
//private:
// int help();
@@ -201,15 +204,18 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//#ifndef A_H_
//#define A_H_
//
+ //#include "B.h"
+ //
//class A {
//public:
// A();
// virtual ~A();
- // int foo();
+ // void foo();
+ // B b;
//
//private:
// int help();
- // int extracted(int i);
+ // void extracted();
//};
//
//#endif /*A_H_*/
@@ -223,12 +229,9 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//A::~A() {
//}
//
- //int A::foo() {
- // int i = 2;
- // //comment
- // /*$*/++i;
+ //void A::foo() {
+ // /*$*/b = new B();
// help();/*$$*/
- // return i;
//}
//
//int A::help() {
@@ -243,69 +246,31 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//A::~A() {
//}
//
- //int A::extracted(int i) {
- // //comment
- // ++i;
+ //void A::extracted() {
+ // b = new B();
// help();
- // return i;
//}
//
- //int A::foo() {
- // int i = 2;
- // //comment
- // i = extracted(i);
- // return i;
+ //void A::foo() {
+ // extracted();
//}
//
//int A::help() {
// return 42;
//}
- public void testComment() throws Exception {
- assertRefactoringSuccess();
- }
- //main.cpp
- //int main() {
- // int i;
- // // Comment
- // /*$*/i= 7;/*$$*/
- // return i;
- //}
- //====================
- //int extracted(int i) {
- // // Comment
- // i = 7;
- // return i;
- //}
+ //B.h
+ //#ifndef B_H_
+ //#define B_H_
//
- //int main() {
- // int i;
- // // Comment
- // i = extracted(i);
- // return i;
- //}
- public void testLeadingComment() throws Exception {
- assertRefactoringSuccess();
- }
-
- //main.cpp
- //int main() {
- // int i;
- // /*$*/i= 7;/*$$*/ // Comment
- // return i;
- //}
- //====================
- //int extracted(int i) {
- // i = 7; // Comment
- // return i;
- //}
+ //class B {
+ //public:
+ // B();
+ // virtual ~B();
+ //};
//
- //int main() {
- // int i;
- // i = extracted(i);
- // return i;
- //}
- public void testTraillingComment() throws Exception {
+ //#endif /*B_H_*/
+ public void testLocalVariableDeclaration_2() throws Exception {
assertRefactoringSuccess();
}
@@ -347,7 +312,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int A::help() {
// return 42;
//}
- public void testTwoVariableDefinedInScope() throws Exception {
+ public void testTwoLocalVariables() throws Exception {
assertRefactoringFailure();
}
@@ -355,14 +320,11 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//#ifndef A_H_
//#define A_H_
//
- //#include "B.h"
- //
//class A {
//public:
// A();
// virtual ~A();
- // void foo();
- // B b;
+ // int foo();
//
//private:
// int help();
@@ -373,18 +335,15 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//#ifndef A_H_
//#define A_H_
//
- //#include "B.h"
- //
//class A {
//public:
// A();
// virtual ~A();
- // void foo();
- // B b;
+ // int foo();
//
//private:
// int help();
- // void extracted();
+ // int extracted(int i);
//};
//
//#endif /*A_H_*/
@@ -398,9 +357,12 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//A::~A() {
//}
//
- //void A::foo() {
- // /*$*/b = new B();
+ //int A::foo() {
+ // int i = 2;
+ // //comment
+ // /*$*/++i;
// help();/*$$*/
+ // return i;
//}
//
//int A::help() {
@@ -415,31 +377,69 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//A::~A() {
//}
//
- //void A::extracted() {
- // b = new B();
+ //int A::extracted(int i) {
+ // //comment
+ // ++i;
// help();
+ // return i;
//}
//
- //void A::foo() {
- // extracted();
+ //int A::foo() {
+ // int i = 2;
+ // //comment
+ // i = extracted(i);
+ // return i;
//}
//
//int A::help() {
// return 42;
//}
+ public void testComment() throws Exception {
+ assertRefactoringSuccess();
+ }
- //B.h
- //#ifndef B_H_
- //#define B_H_
+ //main.cpp
+ //int main() {
+ // int i;
+ // // Comment
+ // /*$*/i= 7;/*$$*/
+ // return i;
+ //}
+ //====================
+ //int extracted(int i) {
+ // // Comment
+ // i = 7;
+ // return i;
+ //}
//
- //class B {
- //public:
- // B();
- // virtual ~B();
- //};
+ //int main() {
+ // int i;
+ // // Comment
+ // i = extracted(i);
+ // return i;
+ //}
+ public void testLeadingComment() throws Exception {
+ assertRefactoringSuccess();
+ }
+
+ //main.cpp
+ //int main() {
+ // int i;
+ // /*$*/i= 7;/*$$*/ // Comment
+ // return i;
+ //}
+ //====================
+ //int extracted(int i) {
+ // i = 7; // Comment
+ // return i;
+ //}
//
- //#endif /*B_H_*/
- public void testNamedTypedField() throws Exception {
+ //int main() {
+ // int i;
+ // i = extracted(i);
+ // return i;
+ //}
+ public void testTraillingComment() throws Exception {
assertRefactoringSuccess();
}
@@ -531,10 +531,9 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//};
//
//#endif /*B_H_*/
- public void testNamedTypedVariableDefinedInScope() throws Exception {
+ public void testNamedTypedField() throws Exception {
assertRefactoringSuccess();
}
-
//A.h
//#ifndef A_H_
//#define A_H_
@@ -647,91 +646,6 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//
//private:
// int help();
- // int extracted(int i);
- //};
- //
- //#endif /*A_H_*/
-
- //A.cpp
- //#include "A.h"
- //
- //#define ADD(a,b) a + b + 2
- //
- //A::A() {
- //}
- //
- //A::~A() {
- //}
- //
- //int A::foo() {
- // int i = 2;
- // /*$*/++i;
- // i = ADD(i, 42);
- // help();/*$$*/
- // return i;
- //}
- //
- //int A::help() {
- // return 42;
- //}
- //====================
- //#include "A.h"
- //
- //#define ADD(a,b) a + b + 2
- //
- //A::A() {
- //}
- //
- //A::~A() {
- //}
- //
- //int A::extracted(int i) {
- // ++i;
- // i = ADD(i, 42);
- // help();
- // return i;
- //}
- //
- //int A::foo() {
- // int i = 2;
- // i = extracted(i);
- // return i;
- //}
- //
- //int A::help() {
- // return 42;
- //}
- public void testFunctionStyleMacro() throws Exception {
- assertRefactoringSuccess();
- }
-
- //A.h
- //#ifndef A_H_
- //#define A_H_
- //
- //class A {
- //public:
- // A();
- // virtual ~A();
- // int foo();
- //
- //private:
- // int help();
- //};
- //
- //#endif /*A_H_*/
- //====================
- //#ifndef A_H_
- //#define A_H_
- //
- //class A {
- //public:
- // A();
- // virtual ~A();
- // int foo();
- //
- //private:
- // int help();
// void extracted(int* j);
//};
//
@@ -1030,7 +944,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int A::help() {
// return 42;
//}
- public void testRefParameter() throws Exception {
+ public void testReturnValueSelection_1() throws Exception {
assertRefactoringSuccess();
}
@@ -1121,7 +1035,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int A::help() {
// return 42;
//}
- public void testRefParameterAndSomeMoreNotUsedAfterwards() throws Exception {
+ public void testReturnValueSelection_2() throws Exception {
assertRefactoringSuccess();
}
@@ -1156,7 +1070,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//
//private:
// int help();
- // float extracted(int& i, int y, float x, B* b);
+ // bool extracted(bool y, float x, int& i, B* b);
//};
//
//#endif /*A_H_*/
@@ -1174,11 +1088,13 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// int i = 2;
// float x = i;
// B* b = new B();
- // int y = x + i;
+ // bool y = false;
// /*$*/++i;
// b->hello(y);
+ // y = !y;
// i = i + x;
// help();/*$$*/
+ // b->hello(y);
// ++x;
// return i;
//}
@@ -1195,20 +1111,22 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//A::~A() {
//}
//
- //float A::extracted(int& i, int y, float x, B* b) {
+ //bool A::extracted(bool y, float x, int& i, B* b) {
// ++i;
// b->hello(y);
+ // y = !y;
// i = i + x;
// help();
- // return x;
+ // return y;
//}
//
//int A::foo() {
// int i = 2;
// float x = i;
// B* b = new B();
- // int y = x + i;
- // x = extracted(i, y, x, b);
+ // bool y = false;
+ // y = extracted(y, x, i, b);
+ // b->hello(y);
// ++x;
// return i;
//}
@@ -1225,12 +1143,11 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//public:
// B();
// virtual ~B();
- // void hello(float y);
+ // void hello(bool y);
//};
//
//#endif /*B_H_*/
- public void testExplicitlyAssignedReturnValue() throws Exception {
- returnValue = "x";
+ public void testReturnValueSelection_3() throws Exception {
assertRefactoringSuccess();
}
@@ -1265,7 +1182,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//
//private:
// int help();
- // bool extracted(bool y, float x, int& i, B* b);
+ // float extracted(int& i, int y, float x, B* b);
//};
//
//#endif /*A_H_*/
@@ -1283,13 +1200,11 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// int i = 2;
// float x = i;
// B* b = new B();
- // bool y = false;
+ // int y = x + i;
// /*$*/++i;
// b->hello(y);
- // y = !y;
// i = i + x;
// help();/*$$*/
- // b->hello(y);
// ++x;
// return i;
//}
@@ -1306,22 +1221,20 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//A::~A() {
//}
//
- //bool A::extracted(bool y, float x, int& i, B* b) {
+ //float A::extracted(int& i, int y, float x, B* b) {
// ++i;
// b->hello(y);
- // y = !y;
// i = i + x;
// help();
- // return y;
+ // return x;
//}
//
//int A::foo() {
// int i = 2;
// float x = i;
// B* b = new B();
- // bool y = false;
- // y = extracted(y, x, i, b);
- // b->hello(y);
+ // int y = x + i;
+ // x = extracted(i, y, x, b);
// ++x;
// return i;
//}
@@ -1338,11 +1251,12 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//public:
// B();
// virtual ~B();
- // void hello(bool y);
+ // void hello(float y);
//};
//
//#endif /*B_H_*/
- public void testReturnValueSelection() throws Exception {
+ public void testExplicitlyAssignedReturnValue() throws Exception {
+ returnValue = "x";
assertRefactoringSuccess();
}
@@ -1698,7 +1612,132 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
assertRefactoringSuccess();
}
- //main.h
+ //test.cpp
+ //int test(bool param) {
+ // int a = 42;
+ // char b = '0';
+ //
+ // if (param) {
+ // /*$*/b += a;
+ // a += b;/*$$*/
+ // } else {
+ // b -= a;
+ // a -= b;
+ // }
+ // return a;
+ //}
+ //====================
+ //int extracted(char b, int a) {
+ // b += a;
+ // a += b;
+ // return a;
+ //}
+ //
+ //int test(bool param) {
+ // int a = 42;
+ // char b = '0';
+ //
+ // if (param) {
+ // a = extracted(b, a);
+ // } else {
+ // b -= a;
+ // a -= b;
+ // }
+ // return a;
+ //}
+ public void testOutputParametersDetectionInIfStatement() throws Exception {
+ assertRefactoringSuccess();
+ }
+
+ //main.c
+ //int main() {
+ // int a = 42;
+ // char b = '0';
+ //
+ // switch (a) {
+ // case 0:
+ // /*$*/b += a;
+ // a += b;/*$$*/
+ // break;
+ // case 42:
+ // b -= a;
+ // a -= b;
+ // break;
+ // default:
+ // b ++;
+ // a += b;
+ // break;
+ // }
+ // return b;
+ //}
+ //====================
+ //char extracted(char b, int a) {
+ // b += a;
+ // a += b;
+ // return b;
+ //}
+ //
+ //int main() {
+ // int a = 42;
+ // char b = '0';
+ //
+ // switch (a) {
+ // case 0:
+ // b = extracted(b, a);
+ // break;
+ // case 42:
+ // b -= a;
+ // a -= b;
+ // break;
+ // default:
+ // b ++;
+ // a += b;
+ // break;
+ // }
+ // return b;
+ //}
+ public void testOutputParametersDetectionInSwitchStatement_Bug302406() throws Exception {
+ assertRefactoringSuccess();
+ }
+
+ //test.c
+ //void print(int i, double a, double b);
+ //
+ //void test(double x) {
+ // double s = 0;
+ // double y = 1;
+ // int i;
+ // for (i = 0; i < 10; i++) {
+ // print(x, s);
+ // /*$*/x *= x;
+ // y *= i;
+ // s += x / y;/*$$*/
+ // }
+ //}
+ //====================
+ //void print(int i, double a, double b);
+ //
+ //extracted(double x, int i, double* y, double* s) {
+ // x *= x;
+ // *y *= i;
+ // *s += x / *y;
+ // return x;
+ //}
+ //
+ //void test(double x) {
+ // double s = 0;
+ // double y = 1;
+ // int i;
+ // for (i = 0; i < 10; i++) {
+ // print(x, s);
+ // x = extracted(x, i, &y, &s);
+ // }
+ //}
+ public void testOutputParametersDetectionInForLoop() throws Exception {
+ assertRefactoringSuccess();
+ }
+
+ //main.cpp
//void method() {
// /*$*/for (int var = 0; var < 100; ++var) {
// if (var < 50)
@@ -1749,39 +1788,6 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//void testFuerRainer() {
// int i = int();
// /*$*/++i;
- // //Leading Comment
- // ASSERT(i);
- // //Trailling Comment
- // --i;/*$$*/
- //}
- //====================
- //#define ASSERTM(msg,cond) if (!(cond)) throw cute::test_failure((msg),__FILE__,__LINE__)
- //#define ASSERT(cond) ASSERTM(#cond, cond)
- //
- //void runTest(int i) {
- // ++i;
- // //Leading Comment
- // ASSERT(i);
- // //Trailling Comment
- // --i;
- //}
- //
- //void testFuerRainer() {
- // int i = int();
- // runTest(i);
- //}
- public void testMacroCallInSelectedCodeForgetsTheMacro() throws Exception {
- extractedFunctionName = "runTest";
- assertRefactoringSuccess();
- }
-
- //Test.cpp
- //#define ASSERTM(msg,cond) if (!(cond)) throw cute::test_failure((msg),__FILE__,__LINE__)
- //#define ASSERT(cond) ASSERTM(#cond, cond)
- //
- //void testFuerRainer() {
- // int i = int();
- // /*$*/++i;
// ASSERT(i);
// --i;/*$$*/
//}
@@ -1835,7 +1841,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// string* newElements = runTest(m_capacity);
// newElements[0] = "s";
//}
- public void testStringArrayProblemInExtractFunction() throws Exception {
+ public void testStringArray() throws Exception {
extractedFunctionName = "runTest";
assertRefactoringSuccess();
}
@@ -1902,7 +1908,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// extracted(b, c, a);
// return a;
//}
- public void testBug239059DoubleAmpersandInSignatureOfExtractedFunctions() throws Exception {
+ public void testReferenceVariable_Bug239059() throws Exception {
assertRefactoringSuccess();
}
@@ -1972,7 +1978,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//void Test::test() {
// RetType v = extracted();
//}
- public void testBug241717TypedefCausesVoidAsReturnType() throws Exception {
+ public void testTypedef_Bug241717() throws Exception {
assertRefactoringSuccess();
}
@@ -2020,7 +2026,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int main() {
// return 0;
//}
- public void testBug248238ExtractMethodProducesWrongReturnTypeOrJustFailsClasstype() throws Exception {
+ public void testQualifiedReturnTypeName_Bug248238_1() throws Exception {
extractedFunctionName = "startTag";
assertRefactoringSuccess();
}
@@ -2072,7 +2078,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int main() {
// return 0;
//}
- public void testBug248238ExtractMethodProducesWrongReturnTypeOrJustFailsTypedef() throws Exception {
+ public void testQualifiedReturnTypeName_Bug248238_2() throws Exception {
extractedFunctionName = "startTag";
assertRefactoringSuccess();
}
@@ -2122,7 +2128,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int main() {
// return 0;
//}
- public void testBug248622ExtractFunctionFailsToExtractSeveralExpressionsSelectionAtTheEnd() throws Exception {
+ public void testReturnStatementExpression_Bug248622_1() throws Exception {
extractedFunctionName = "endTag";
assertRefactoringSuccess();
}
@@ -2172,7 +2178,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int main() {
// return 0;
//}
- public void testBug248622ExtractFunctionFailsToExtractSeveralExpressionsSelectionInTheMiddle() throws Exception {
+ public void testReturnStatementExpression_Bug248622_2() throws Exception {
assertRefactoringSuccess();
}
@@ -2194,7 +2200,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int main(int argc, char** argv) {
// extracted();
//}
- public void testBug262000ExtractFunctionMisinterpretsArtificialBlocks() throws Exception {
+ public void testBlock_Bug262000() throws Exception {
assertRefactoringSuccess();
}
@@ -2299,7 +2305,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// int result = extracted();
// return result;
//}
- public void testBug264712ExtractFunctionDeletesCommentsInHeader() throws Exception {
+ public void testCommentsInHeader_Bug264712() throws Exception {
assertRefactoringSuccess();
}
@@ -2338,7 +2344,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// a = extracted(a);
// return a;
//}
- public void testBug281564ExtractFunctionFailsWhenCatchingAnUnnamedException() throws Exception {
+ public void testCatchUnnamedException_Bug281564() throws Exception {
assertRefactoringSuccess();
}
@@ -2358,7 +2364,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// extracted(b, a);
// return a;
//}
- public void testBug282004ExtractFunctionInCProjectNotCPPWontExtractParameters() throws Exception {
+ public void testCFunction_Bug282004() throws Exception {
assertRefactoringSuccess();
}
@@ -2379,7 +2385,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// a = extracted(a, b);
// return a;
//}
- public void testBug288268CRefactoringCreatesCPPParameters() throws Exception {
+ public void testCFunction_Bug288268() throws Exception {
assertRefactoringSuccess();
}
@@ -3359,7 +3365,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//};
//
//#endif /*B_H_*/
- public void testALotRefParameterAndAMethodCall() throws Exception {
+ public void testMethodCall() throws Exception {
assertRefactoringSuccess();
}
@@ -3486,7 +3492,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//};
//
//#endif /*B_H_*/
- public void testALotRefParameterAndAMethodCallDuplicateIsSimilar() throws Exception {
+ public void testMethodCallWithDuplicate() throws Exception {
assertRefactoringSuccess();
}
@@ -3601,6 +3607,91 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//
//private:
// int help();
+ // int extracted(int i);
+ //};
+ //
+ //#endif /*A_H_*/
+
+ //A.cpp
+ //#include "A.h"
+ //
+ //#define ADD(a,b) a + b + 2
+ //
+ //A::A() {
+ //}
+ //
+ //A::~A() {
+ //}
+ //
+ //int A::foo() {
+ // int i = 2;
+ // /*$*/++i;
+ // i = ADD(i, 42);
+ // help();/*$$*/
+ // return i;
+ //}
+ //
+ //int A::help() {
+ // return 42;
+ //}
+ //====================
+ //#include "A.h"
+ //
+ //#define ADD(a,b) a + b + 2
+ //
+ //A::A() {
+ //}
+ //
+ //A::~A() {
+ //}
+ //
+ //int A::extracted(int i) {
+ // ++i;
+ // i = ADD(i, 42);
+ // help();
+ // return i;
+ //}
+ //
+ //int A::foo() {
+ // int i = 2;
+ // i = extracted(i);
+ // return i;
+ //}
+ //
+ //int A::help() {
+ // return 42;
+ //}
+ public void testFunctionStyleMacro_1() throws Exception {
+ assertRefactoringSuccess();
+ }
+
+ //A.h
+ //#ifndef A_H_
+ //#define A_H_
+ //
+ //class A {
+ //public:
+ // A();
+ // virtual ~A();
+ // int foo();
+ //
+ //private:
+ // int help();
+ //};
+ //
+ //#endif /*A_H_*/
+ //====================
+ //#ifndef A_H_
+ //#define A_H_
+ //
+ //class A {
+ //public:
+ // A();
+ // virtual ~A();
+ // int foo();
+ //
+ //private:
+ // int help();
// int extracted(int ii);
//};
//
@@ -3655,7 +3746,40 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int A::help() {
// return 42;
//}
- public void testFunctionStyleMacro2() throws Exception {
+ public void testFunctionStyleMacro_2() throws Exception {
+ assertRefactoringSuccess();
+ }
+
+ //Test.cpp
+ //#define ASSERTM(msg,cond) if (!(cond)) throw cute::test_failure((msg),__FILE__,__LINE__)
+ //#define ASSERT(cond) ASSERTM(#cond, cond)
+ //
+ //void testFuerRainer() {
+ // int i = int();
+ // /*$*/++i;
+ // //Leading Comment
+ // ASSERT(i);
+ // //Trailling Comment
+ // --i;/*$$*/
+ //}
+ //====================
+ //#define ASSERTM(msg,cond) if (!(cond)) throw cute::test_failure((msg),__FILE__,__LINE__)
+ //#define ASSERT(cond) ASSERTM(#cond, cond)
+ //
+ //void runTest(int i) {
+ // ++i;
+ // //Leading Comment
+ // ASSERT(i);
+ // //Trailling Comment
+ // --i;
+ //}
+ //
+ //void testFuerRainer() {
+ // int i = int();
+ // runTest(i);
+ //}
+ public void testFunctionStyleMacro_3() throws Exception {
+ extractedFunctionName = "runTest";
assertRefactoringSuccess();
}
@@ -3744,7 +3868,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int A::help() {
// return 42;
//}
- public void testReturnValueAssignedToMacroCall() throws Exception {
+ public void testReturnValueAssignedInMacro() throws Exception {
returnValue = "b";
assertRefactoringSuccess();
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/BlockFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/BlockFlowInfo.java
new file mode 100644
index 00000000000..4fea1068010
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/BlockFlowInfo.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class BlockFlowInfo extends GenericSequentialFlowInfo {
+
+ public BlockFlowInfo() {
+ }
+}
+
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/BranchFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/BranchFlowInfo.java
new file mode 100644
index 00000000000..bc2452b89bd
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/BranchFlowInfo.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+import java.util.HashSet;
+
+import org.eclipse.cdt.core.dom.ast.IASTName;
+
+class BranchFlowInfo extends FlowInfo {
+
+ public BranchFlowInfo(IASTName label, FlowContext context) {
+ super(NO_RETURN);
+ fBranches= new HashSet<String>(2);
+ fBranches.add(makeString(label));
+ }
+}
+
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ConditionalFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ConditionalFlowInfo.java
new file mode 100644
index 00000000000..64474ab1366
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ConditionalFlowInfo.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class ConditionalFlowInfo extends FlowInfo {
+
+ public ConditionalFlowInfo() {
+ super(NO_RETURN);
+ }
+
+ public void mergeCondition(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeAccessModeSequential(info, context);
+ }
+
+ public void merge(FlowInfo truePart, FlowInfo falsePart, FlowContext context) {
+ if (truePart == null && falsePart == null)
+ return;
+
+ GenericConditionalFlowInfo cond= new GenericConditionalFlowInfo();
+ if (truePart != null)
+ cond.mergeAccessMode(truePart, context);
+
+ if (falsePart != null)
+ cond.mergeAccessMode(falsePart, context);
+
+ if (truePart == null || falsePart == null)
+ cond.mergeEmptyCondition(context);
+
+ mergeAccessModeSequential(cond, context);
+ }
+}
+
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/DoWhileFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/DoWhileFlowInfo.java
new file mode 100644
index 00000000000..93a0febee8b
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/DoWhileFlowInfo.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class DoWhileFlowInfo extends FlowInfo {
+ private boolean fActionBranches;
+
+ public void mergeAction(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ fActionBranches= info.branches();
+
+ assign(info);
+
+ if (fActionBranches && fReturnKind == VALUE_RETURN) {
+ fReturnKind= PARTIAL_RETURN;
+ }
+ }
+
+ public void mergeCondition(FlowInfo info, FlowContext context) {
+ if (fActionBranches || fReturnKind == VALUE_RETURN || fReturnKind == VOID_RETURN || info == null)
+ return;
+ mergeAccessModeSequential(info, context);
+ }
+}
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowAnalyzer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowAnalyzer.java
new file mode 100644
index 00000000000..4047665a564
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowAnalyzer.java
@@ -0,0 +1,1012 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
+
+import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor;
+import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
+import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
+import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
+import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
+import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
+import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
+import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
+import org.eclipse.cdt.core.dom.ast.IASTContinueStatement;
+import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
+import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTDefaultStatement;
+import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
+import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTExpression;
+import org.eclipse.cdt.core.dom.ast.IASTExpressionList;
+import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
+import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
+import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IASTForStatement;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
+import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
+import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
+import org.eclipse.cdt.core.dom.ast.IASTInitializerList;
+import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
+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.IASTNullStatement;
+import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTProblemExpression;
+import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
+import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTStatement;
+import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
+import org.eclipse.cdt.core.dom.ast.IASTTypeIdInitializerExpression;
+import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
+import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.IField;
+import org.eclipse.cdt.core.dom.ast.IVariable;
+import org.eclipse.cdt.core.dom.ast.c.ICASTDesignatedInitializer;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement;
+import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator;
+
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVariableReadWriteFlags;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
+
+/**
+ * Special flow analyzer to determine the return value of the extracted method
+ * and the variables which have to be passed to the method.
+ *
+ * Note: This analyzer doesn't do a full flow analysis. For example it doesn't
+ * do dead code analysis or variable initialization analysis. It analyzes
+ * the first access to a variable (read or write) and if all execution paths
+ * return a value.
+ */
+abstract class FlowAnalyzer extends ASTGenericVisitor {
+
+ static protected class SwitchData {
+ private boolean fHasDefaultCase;
+ private final List<IRegion> fRanges= new ArrayList<IRegion>(4);
+ private final List<FlowInfo> fInfos= new ArrayList<FlowInfo>(4);
+
+ public void setHasDefaultCase() {
+ fHasDefaultCase= true;
+ }
+
+ public boolean hasDefaultCase() {
+ return fHasDefaultCase;
+ }
+
+ public void add(IRegion range, FlowInfo info) {
+ fRanges.add(range);
+ fInfos.add(info);
+ }
+
+ public IRegion[] getRanges() {
+ return fRanges.toArray(new IRegion[fRanges.size()]);
+ }
+
+ public FlowInfo[] getInfos() {
+ return fInfos.toArray(new FlowInfo[fInfos.size()]);
+ }
+
+ public FlowInfo getInfo(int index) {
+ return fInfos.get(index);
+ }
+ }
+
+ private final HashMap<IASTNode, FlowInfo> fData = new HashMap<IASTNode, FlowInfo>(100);
+ FlowContext fFlowContext;
+
+ public FlowAnalyzer(FlowContext context) {
+ super(true);
+ fFlowContext= context;
+ }
+
+ protected abstract boolean createReturnFlowInfo(IASTReturnStatement node);
+
+ protected abstract boolean traverseNode(IASTNode node);
+
+ protected boolean skipNode(IASTNode node) {
+ return !traverseNode(node);
+ }
+
+ @Override
+ protected final int genericVisit(IASTNode node) {
+ return traverseNode(node) ? PROCESS_CONTINUE : PROCESS_SKIP;
+ }
+
+ //---- Hooks to create Flow info objects. User may introduce their own infos.
+
+ protected ReturnFlowInfo createReturn(IASTReturnStatement statement) {
+ return new ReturnFlowInfo(statement);
+ }
+
+ protected ThrowFlowInfo createThrow() {
+ return new ThrowFlowInfo();
+ }
+
+ protected BranchFlowInfo createBranch(IASTName label) {
+ return new BranchFlowInfo(label, fFlowContext);
+ }
+
+ protected GenericSequentialFlowInfo createSequential() {
+ return new GenericSequentialFlowInfo();
+ }
+
+ protected ConditionalFlowInfo createConditional() {
+ return new ConditionalFlowInfo();
+ }
+
+ protected RangeBasedForFlowInfo createEnhancedFor() {
+ return new RangeBasedForFlowInfo();
+ }
+
+ protected ForFlowInfo createFor() {
+ return new ForFlowInfo();
+ }
+
+ protected TryFlowInfo createTry() {
+ return new TryFlowInfo();
+ }
+
+ protected WhileFlowInfo createWhile() {
+ return new WhileFlowInfo();
+ }
+
+ protected IfFlowInfo createIf() {
+ return new IfFlowInfo();
+ }
+
+ protected DoWhileFlowInfo createDoWhile() {
+ return new DoWhileFlowInfo();
+ }
+
+ protected SwitchFlowInfo createSwitch() {
+ return new SwitchFlowInfo();
+ }
+
+ protected BlockFlowInfo createBlock() {
+ return new BlockFlowInfo();
+ }
+
+ protected FunctionCallFlowInfo createFunctionCallFlowInfo() {
+ return new FunctionCallFlowInfo();
+ }
+
+ protected FlowContext getFlowContext() {
+ return fFlowContext;
+ }
+
+ //---- Helpers to access flow analysis objects ----------------------------------------
+
+ protected FlowInfo getFlowInfo(IASTNode node) {
+ return fData.remove(node);
+ }
+
+ protected void setFlowInfo(IASTNode node, FlowInfo info) {
+ fData.put(node, info);
+ }
+
+ protected FlowInfo assignFlowInfo(IASTNode target, IASTNode source) {
+ FlowInfo result= getFlowInfo(source);
+ setFlowInfo(target, result);
+ return result;
+ }
+
+ protected FlowInfo accessFlowInfo(IASTNode node) {
+ return fData.get(node);
+ }
+
+ //---- Helpers to process sequential flow infos -------------------------------------
+
+ protected GenericSequentialFlowInfo processSequential(IASTNode parent, IASTNode[] nodes) {
+ GenericSequentialFlowInfo result= createSequential(parent);
+ process(result, nodes);
+ return result;
+ }
+
+ protected GenericSequentialFlowInfo processSequential(IASTNode parent, Iterable<IASTNode> nodes) {
+ GenericSequentialFlowInfo result= createSequential(parent);
+ process(result, nodes);
+ return result;
+ }
+
+ protected GenericSequentialFlowInfo processSequential(IASTNode parent, IASTNode node) {
+ GenericSequentialFlowInfo result= createSequential(parent);
+ if (node != null)
+ result.merge(getFlowInfo(node), fFlowContext);
+ return result;
+ }
+
+ protected GenericSequentialFlowInfo processSequential(IASTNode parent, IASTNode node1, IASTNode node2) {
+ GenericSequentialFlowInfo result= createSequential(parent);
+ if (node1 != null)
+ result.merge(getFlowInfo(node1), fFlowContext);
+ if (node2 != null)
+ result.merge(getFlowInfo(node2), fFlowContext);
+ return result;
+ }
+
+ protected GenericSequentialFlowInfo createSequential(IASTNode parent) {
+ GenericSequentialFlowInfo result= createSequential();
+ setFlowInfo(parent, result);
+ return result;
+ }
+
+ protected GenericSequentialFlowInfo createSequential(IASTNode[] nodes) {
+ GenericSequentialFlowInfo result= createSequential();
+ process(result, nodes);
+ return result;
+ }
+
+ //---- Generic merge methods --------------------------------------------------------
+
+ protected void process(GenericSequentialFlowInfo info, IASTNode[] nodes) {
+ if (nodes == null)
+ return;
+ for (IASTNode node : nodes) {
+ info.merge(getFlowInfo(node), fFlowContext);
+ }
+ }
+
+ protected void process(GenericSequentialFlowInfo info, Iterable<IASTNode> nodes) {
+ if (nodes == null)
+ return;
+ for (IASTNode node : nodes) {
+ info.merge(getFlowInfo(node), fFlowContext);
+ }
+ }
+
+ protected void process(GenericSequentialFlowInfo info, IASTNode node) {
+ if (node != null)
+ info.merge(getFlowInfo(node), fFlowContext);
+ }
+
+ protected void process(GenericSequentialFlowInfo info, IASTNode node1, IASTNode node2) {
+ if (node1 != null)
+ info.merge(getFlowInfo(node1), fFlowContext);
+ if (node2 != null)
+ info.merge(getFlowInfo(node2), fFlowContext);
+ }
+
+ //---- special visit methods -------------------------------------------------------
+
+ @Override
+ public int visit(IASTStatement node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ if (node instanceof IASTBreakStatement) {
+ return visit((IASTBreakStatement) node);
+ } else if (node instanceof IASTCaseStatement) {
+ return visit((IASTCaseStatement) node);
+ } else if (node instanceof IASTCompoundStatement) {
+ return visit((IASTCompoundStatement) node);
+ } else if (node instanceof IASTContinueStatement) {
+ return visit((IASTContinueStatement) node);
+ } else if (node instanceof IASTDeclarationStatement) {
+ return visit((IASTDeclarationStatement) node);
+ } else if (node instanceof IASTDefaultStatement) {
+ return visit((IASTDefaultStatement) node);
+ } else if (node instanceof IASTDoStatement) {
+ return visit((IASTDoStatement) node);
+ } else if (node instanceof IASTExpressionStatement) {
+ return visit((IASTExpressionStatement) node);
+ } else if (node instanceof IASTForStatement) {
+ return visit((IASTForStatement) node);
+ } else if (node instanceof IASTGotoStatement) {
+ return visit((IASTGotoStatement) node);
+ } else if (node instanceof IASTIfStatement) {
+ return visit((IASTIfStatement) node);
+ } else if (node instanceof IASTLabelStatement) {
+ return visit((IASTLabelStatement) node);
+ } else if (node instanceof IASTNullStatement) {
+ return visit((IASTNullStatement) node);
+ } else if (node instanceof IASTReturnStatement) {
+ return visit((IASTReturnStatement) node);
+ } else if (node instanceof IASTSwitchStatement) {
+ return visit((IASTSwitchStatement) node);
+ } else if (node instanceof IASTWhileStatement) {
+ return visit((IASTWhileStatement) node);
+ } else if (node instanceof ICPPASTCatchHandler) {
+ return visit((ICPPASTCatchHandler) node);
+ } else if (node instanceof ICPPASTRangeBasedForStatement) {
+ return visit((ICPPASTRangeBasedForStatement) node);
+ } else if (node instanceof ICPPASTTryBlockStatement) {
+ return visit((ICPPASTTryBlockStatement) node);
+ }
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTBreakStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTCaseStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTDefaultStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTCompoundStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTContinueStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTDeclarationStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTDoStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTExpressionStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTForStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTGotoStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTIfStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTLabelStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTNullStatement node) {
+ // Null statements aren't of any interest.
+ return PROCESS_SKIP;
+ }
+
+ public int visit(ICPPASTRangeBasedForStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(ICPPASTTryBlockStatement node) {
+ if (traverseNode(node)) {
+ fFlowContext.pushExceptions(node);
+ node.getTryBody().accept(this);
+ fFlowContext.popExceptions();
+ for (ICPPASTCatchHandler catchHandler : node.getCatchHandlers()) {
+ catchHandler.accept(this);
+ }
+ }
+ return PROCESS_SKIP;
+ }
+
+ public int visit(ICPPASTCatchHandler node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTReturnStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTSwitchStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int visit(IASTWhileStatement node) {
+ return PROCESS_CONTINUE;
+ }
+
+ //---- Helper to process switch statement ----------------------------------------
+
+ protected SwitchData createSwitchData(IASTSwitchStatement node) {
+ SwitchData result= new SwitchData();
+ IASTStatement[] statements;
+ IASTStatement body = node.getBody();
+ if (body instanceof IASTCompoundStatement) {
+ statements = ((IASTCompoundStatement) body).getStatements();
+ } else {
+ statements = new IASTStatement[] { body };
+ }
+ if (statements.length == 0)
+ return result;
+
+ int start= -1;
+ int end= -1;
+ GenericSequentialFlowInfo info= null;
+
+ for (IASTStatement statement : statements) {
+ IASTFileLocation location = statement.getFileLocation();
+ if (statement instanceof IASTCaseStatement || statement instanceof IASTDefaultStatement) {
+ if (statement instanceof IASTDefaultStatement) {
+ result.setHasDefaultCase();
+ }
+ if (info == null) {
+ info= createSequential();
+ start= location.getNodeOffset();
+ } else {
+ if (info.isReturn() || info.isPartialReturn() || info.branches()) {
+ result.add(new Region(start, end - start + 1), info);
+ info= createSequential();
+ start= location.getNodeOffset();
+ }
+ }
+ } else {
+ if (info == null) {
+ info= createSequential();
+ start= location.getNodeOffset();
+ } else {
+ info.merge(getFlowInfo(statement), fFlowContext);
+ }
+ }
+ end= location.getNodeOffset() + location.getNodeLength() - 1;
+ }
+ result.add(new Region(start, end - start + 1), info);
+ return result;
+ }
+
+ //---- Concrete leave methods ---------------------------------------------------
+
+ @Override
+ public int leave(IASTStatement node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ if (node instanceof IASTBreakStatement) {
+ return leave((IASTBreakStatement) node);
+ } else if (node instanceof IASTCaseStatement) {
+ return leave((IASTCaseStatement) node);
+ } else if (node instanceof IASTCompoundStatement) {
+ return leave((IASTCompoundStatement) node);
+ } else if (node instanceof IASTContinueStatement) {
+ return leave((IASTContinueStatement) node);
+ } else if (node instanceof IASTDeclarationStatement) {
+ return leave((IASTDeclarationStatement) node);
+ } else if (node instanceof IASTDefaultStatement) {
+ return leave((IASTDefaultStatement) node);
+ } else if (node instanceof IASTDoStatement) {
+ return leave((IASTDoStatement) node);
+ } else if (node instanceof IASTExpressionStatement) {
+ return leave((IASTExpressionStatement) node);
+ } else if (node instanceof IASTForStatement) {
+ return leave((IASTForStatement) node);
+ } else if (node instanceof IASTGotoStatement) {
+ return leave((IASTGotoStatement) node);
+ } else if (node instanceof IASTIfStatement) {
+ return leave((IASTIfStatement) node);
+ } else if (node instanceof IASTLabelStatement) {
+ return leave((IASTLabelStatement) node);
+ } else if (node instanceof IASTNullStatement) {
+ return leave((IASTNullStatement) node);
+ } else if (node instanceof IASTReturnStatement) {
+ return leave((IASTReturnStatement) node);
+ } else if (node instanceof IASTSwitchStatement) {
+ return leave((IASTSwitchStatement) node);
+ } else if (node instanceof IASTWhileStatement) {
+ return leave((IASTWhileStatement) node);
+ } else if (node instanceof ICPPASTCatchHandler) {
+ return leave((ICPPASTCatchHandler) node);
+ } else if (node instanceof ICPPASTRangeBasedForStatement) {
+ return leave((ICPPASTRangeBasedForStatement) node);
+ } else if (node instanceof ICPPASTTryBlockStatement) {
+ return leave((ICPPASTTryBlockStatement) node);
+ }
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTBreakStatement node) {
+ setFlowInfo(node, createBranch(null));
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTCaseStatement node) {
+ // Nothing to do
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTDefaultStatement node) {
+ // Nothing to do
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTCompoundStatement node) {
+ BlockFlowInfo info= createBlock();
+ setFlowInfo(node, info);
+ process(info, node.getStatements());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTContinueStatement node) {
+ setFlowInfo(node, createBranch(null));
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTDeclarationStatement node) {
+ processSequential(node, node.getDeclaration());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTDoStatement node) {
+ DoWhileFlowInfo info= createDoWhile();
+ setFlowInfo(node, info);
+ info.mergeAction(getFlowInfo(node.getBody()), fFlowContext);
+ info.mergeCondition(getFlowInfo(node.getCondition()), fFlowContext);
+ info.removeLabel(null);
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTExpressionStatement node) {
+ assignFlowInfo(node, node.getExpression());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTForStatement node) {
+ ForFlowInfo forInfo= createFor();
+ setFlowInfo(node, forInfo);
+ forInfo.mergeInitializer(createSequential(node.getInitializerStatement()), fFlowContext);
+ forInfo.mergeCondition(getFlowInfo(node.getConditionExpression()), fFlowContext);
+ forInfo.mergeAction(getFlowInfo(node.getBody()), fFlowContext);
+ // Increments are executed after the body.
+ forInfo.mergeIncrement(createSequential(node.getIterationExpression()), fFlowContext);
+ forInfo.removeLabel(null);
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTGotoStatement node) {
+ // TODO(sprigogin): Implement goto support
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTIfStatement node) {
+ IfFlowInfo info= createIf();
+ setFlowInfo(node, info);
+ info.mergeCondition(getFlowInfo(node.getConditionExpression()), fFlowContext);
+ info.merge(getFlowInfo(node.getThenClause()), getFlowInfo(node.getElseClause()), fFlowContext);
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTLabelStatement node) {
+ FlowInfo info= assignFlowInfo(node, node.getNestedStatement());
+ if (info != null)
+ info.removeLabel(node.getName());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTNullStatement node) {
+ // Leaf node.
+ return PROCESS_SKIP;
+ }
+
+ public int leave(ICPPASTRangeBasedForStatement node) {
+ RangeBasedForFlowInfo forInfo= createEnhancedFor();
+ setFlowInfo(node, forInfo);
+ forInfo.mergeDeclaration(getFlowInfo(node.getDeclaration()), fFlowContext);
+ forInfo.mergeInitializerClause(getFlowInfo(node.getInitializerClause()), fFlowContext);
+ forInfo.mergeAction(getFlowInfo(node.getBody()), fFlowContext);
+ forInfo.removeLabel(null);
+ return PROCESS_SKIP;
+ }
+
+ public int leave(ICPPASTTryBlockStatement node) {
+ TryFlowInfo info= createTry();
+ setFlowInfo(node, info);
+ info.mergeTry(getFlowInfo(node.getTryBody()), fFlowContext);
+ for (ICPPASTCatchHandler catchHandler : node.getCatchHandlers()) {
+ info.mergeCatch(getFlowInfo(catchHandler), fFlowContext);
+ }
+ return PROCESS_SKIP;
+ }
+
+ public int leave(ICPPASTCatchHandler node) {
+ processSequential(node, node.getDeclaration(), node.getCatchBody());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTReturnStatement node) {
+ if (createReturnFlowInfo(node)) {
+ ReturnFlowInfo info= createReturn(node);
+ setFlowInfo(node, info);
+ info.merge(getFlowInfo(node.getReturnArgument()), fFlowContext);
+ } else {
+ assignFlowInfo(node, node.getReturnArgument());
+ }
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTSwitchStatement node) {
+ return leave(node, createSwitchData(node));
+ }
+
+ protected int leave(IASTSwitchStatement node, SwitchData data) {
+ SwitchFlowInfo switchFlowInfo= createSwitch();
+ setFlowInfo(node, switchFlowInfo);
+ switchFlowInfo.mergeTest(getFlowInfo(node.getControllerExpression()), fFlowContext);
+ FlowInfo[] cases= data.getInfos();
+ for (int i= 0; i < cases.length; i++) {
+ switchFlowInfo.mergeCase(cases[i], fFlowContext);
+ }
+ switchFlowInfo.mergeDefault(data.hasDefaultCase(), fFlowContext);
+ switchFlowInfo.removeLabel(null);
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTWhileStatement node) {
+ WhileFlowInfo info= createWhile();
+ setFlowInfo(node, info);
+ info.mergeCondition(getFlowInfo(node.getCondition()), fFlowContext);
+ info.mergeAction(getFlowInfo(node.getBody()), fFlowContext);
+ info.removeLabel(null);
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTExpression node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ if (node instanceof IASTArraySubscriptExpression) {
+ return leave((IASTArraySubscriptExpression) node);
+ } else if (node instanceof IASTConditionalExpression) {
+ return leave((IASTConditionalExpression) node);
+ } else if (node instanceof IASTFunctionCallExpression) {
+ return leave((IASTFunctionCallExpression) node);
+ } else if (node instanceof IASTExpressionList) {
+ return leave((IASTExpressionList) node);
+ } else if (node instanceof IASTTypeIdExpression) {
+ return leave((IASTTypeIdExpression) node);
+ } else if (node instanceof IASTBinaryExpression) {
+ return leave((IASTBinaryExpression) node);
+ } else if (node instanceof IASTLiteralExpression) {
+ return leave((IASTLiteralExpression) node);
+ } else if (node instanceof IASTIdExpression) {
+ return leave((IASTIdExpression) node);
+ } else if (node instanceof IASTCastExpression) {
+ return leave((IASTCastExpression) node);
+ } else if (node instanceof IASTUnaryExpression) {
+ return leave((IASTUnaryExpression) node);
+ } else if (node instanceof IASTFieldReference) {
+ return leave((IASTFieldReference) node);
+ } else if (node instanceof IASTTypeIdInitializerExpression) {
+ return leave((IASTTypeIdInitializerExpression) node);
+ } else if (node instanceof ICPPASTNewExpression) {
+ return leave((ICPPASTNewExpression) node);
+ } else if (node instanceof ICPPASTDeleteExpression) {
+ return leave((ICPPASTDeleteExpression) node);
+ } else if (node instanceof ICPPASTSimpleTypeConstructorExpression) {
+ return leave((ICPPASTSimpleTypeConstructorExpression) node);
+ } else if (node instanceof IASTProblemExpression) {
+ return leave(node);
+ }
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTArraySubscriptExpression node) {
+ processSequential(node, node.getArrayExpression(), node.getArgument());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTConditionalExpression node) {
+ ConditionalFlowInfo info= createConditional();
+ setFlowInfo(node, info);
+ info.mergeCondition(getFlowInfo(node.getLogicalConditionExpression()), fFlowContext);
+ info.merge(getFlowInfo(node.getPositiveResultExpression()),
+ getFlowInfo(node.getNegativeResultExpression()), fFlowContext);
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTFunctionCallExpression node) {
+ processFunctionCall(node, node.getFunctionNameExpression(), node.getArguments());
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTDeclaration node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ if (node instanceof IASTFunctionDefinition) {
+ return leave((IASTFunctionDefinition) node);
+ } else if (node instanceof IASTSimpleDeclaration) {
+ return leave((IASTSimpleDeclaration) node);
+ }
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTFunctionDefinition node) {
+ GenericSequentialFlowInfo info= processSequential(node, node.getDeclSpecifier());
+ process(info, node.getDeclarator());
+ process(info, node.getBody());
+ if (node instanceof ICPPASTFunctionWithTryBlock) {
+ process(info, ((ICPPASTFunctionWithTryBlock) node).getCatchHandlers());
+ }
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTSimpleDeclaration node) {
+ GenericSequentialFlowInfo info= processSequential(node, node.getDeclSpecifier());
+ process(info, node.getDeclarators());
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTParameterDeclaration node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ GenericSequentialFlowInfo info= processSequential(node, node.getDeclSpecifier());
+ process(info, node.getDeclarator());
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTDeclarator node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ IASTNode nestedOrName = node.getNestedDeclarator();
+ if (nestedOrName == null)
+ nestedOrName = node.getName();
+ GenericSequentialFlowInfo info= processSequential(node, nestedOrName);
+ if (node instanceof IASTArrayDeclarator)
+ process(info, ((IASTArrayDeclarator) node).getArrayModifiers());
+ IASTNode[] parameters = null;
+ if (node instanceof IASTStandardFunctionDeclarator) {
+ parameters = ((IASTStandardFunctionDeclarator) node).getParameters();
+ } else if (node instanceof ICASTKnRFunctionDeclarator) {
+ parameters = ((ICASTKnRFunctionDeclarator) node).getParameterDeclarations();
+ }
+ if (parameters != null)
+ process(info, parameters);
+ process(info, node.getInitializer());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTExpressionList node) {
+ IASTExpression[] expressions = node.getExpressions();
+ processSequential(node, expressions);
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTTypeIdExpression node) {
+ assignFlowInfo(node, node.getTypeId());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTBinaryExpression node) {
+ int operator = node.getOperator();
+ switch (operator) {
+ case IASTBinaryExpression.op_assign:
+ case IASTBinaryExpression.op_binaryAndAssign:
+ case IASTBinaryExpression.op_binaryOrAssign:
+ case IASTBinaryExpression.op_binaryXorAssign:
+ case IASTBinaryExpression.op_divideAssign:
+ case IASTBinaryExpression.op_minusAssign:
+ case IASTBinaryExpression.op_moduloAssign:
+ case IASTBinaryExpression.op_multiplyAssign:
+ case IASTBinaryExpression.op_plusAssign:
+ case IASTBinaryExpression.op_shiftLeftAssign:
+ case IASTBinaryExpression.op_shiftRightAssign:
+ FlowInfo lhs= getFlowInfo(node.getOperand1());
+ FlowInfo rhs= getFlowInfo(node.getOperand2());
+ if (lhs instanceof LocalFlowInfo) {
+ LocalFlowInfo llhs= (LocalFlowInfo) lhs;
+ llhs.setWriteAccess(fFlowContext);
+ if (operator != IASTBinaryExpression.op_assign) {
+ GenericSequentialFlowInfo tmp= createSequential();
+ tmp.merge(new LocalFlowInfo(llhs, FlowInfo.READ, fFlowContext), fFlowContext);
+ tmp.merge(rhs, fFlowContext);
+ rhs= tmp;
+ }
+ }
+ GenericSequentialFlowInfo info= createSequential(node);
+ // First process right and side and then left hand side.
+ info.merge(rhs, fFlowContext);
+ info.merge(lhs, fFlowContext);
+ break;
+
+ default:
+ IASTExpression[] operands = CPPVisitor.getOperandsOfMultiExpression(node);
+ processSequential(node, operands);
+ break;
+ }
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTLiteralExpression node) {
+ // Leaf node.
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTIdExpression node) {
+ assignFlowInfo(node, node.getName());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTCastExpression node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ processSequential(node, node.getTypeId(), node.getOperand());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTUnaryExpression node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ int operator = node.getOperator();
+
+ switch (operator) {
+ case IASTUnaryExpression.op_prefixIncr:
+ case IASTUnaryExpression.op_prefixDecr:
+ case IASTUnaryExpression.op_postFixIncr:
+ case IASTUnaryExpression.op_postFixDecr: {
+ FlowInfo info= getFlowInfo(node.getOperand());
+ if (info instanceof LocalFlowInfo) {
+ // Normally this should be done in the parent node since the write access takes
+ // place later. But there seems to be no case where this influences the flow
+ // analysis. So it is kept here to simplify the code.
+ GenericSequentialFlowInfo result= createSequential(node);
+ result.merge(info, fFlowContext);
+ result.merge(new LocalFlowInfo((LocalFlowInfo)info, FlowInfo.WRITE, fFlowContext),
+ fFlowContext);
+ } else {
+ setFlowInfo(node, info);
+ }
+ break;
+ }
+ case IASTUnaryExpression.op_throw: {
+ ThrowFlowInfo info= createThrow();
+ setFlowInfo(node, info);
+ IASTExpression expression= node.getOperand();
+ info.merge(getFlowInfo(expression), fFlowContext);
+ break;
+ }
+ case IASTUnaryExpression.op_alignOf:
+ case IASTUnaryExpression.op_sizeof:
+ case IASTUnaryExpression.op_sizeofParameterPack:
+ case IASTUnaryExpression.op_typeid:
+ break;
+
+ default:
+ assignFlowInfo(node, node.getOperand());
+ break;
+ }
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTName node) {
+ if (skipNode(node) || node.isDeclaration() || node instanceof ICPPASTQualifiedName)
+ return PROCESS_SKIP;
+ IBinding binding= node.resolveBinding();
+ if (binding instanceof IVariable) {
+ IVariable variable= (IVariable) binding;
+ if (!(variable instanceof IField)) {
+ int accessMode = CPPVariableReadWriteFlags.getReadWriteFlags(node);
+ setFlowInfo(node, new LocalFlowInfo(variable, accessMode, fFlowContext));
+ }
+ }
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTFieldReference node) {
+ processSequential(node, node.getFieldOwner(), node.getFieldName());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTTypeIdInitializerExpression node) {
+ processSequential(node, node.getInitializer());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(ICPPASTNewExpression node) {
+ GenericSequentialFlowInfo info= processSequential(node, node.getTypeId());
+ process(info, node.getPlacementArguments());
+ process(info, node.getInitializer());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(ICPPASTDeleteExpression node) {
+ assignFlowInfo(node, node.getOperand());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(ICPPASTSimpleTypeConstructorExpression node) {
+ processSequential(node, node.getDeclSpecifier(), node.getInitializer());
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTInitializer node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ if (node instanceof IASTEqualsInitializer) {
+ return leave((IASTEqualsInitializer) node);
+ } else if (node instanceof IASTInitializerList) {
+ return leave((IASTInitializerList) node);
+ } else if (node instanceof ICASTDesignatedInitializer) {
+ return leave((ICASTDesignatedInitializer) node);
+ } else if (node instanceof IASTInitializerList) {
+ return leave((ICPPASTConstructorChainInitializer) node);
+ } else if (node instanceof IASTInitializerList) {
+ return leave((ICPPASTConstructorInitializer) node);
+ }
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTEqualsInitializer node) {
+ assignFlowInfo(node, node.getInitializerClause());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(IASTInitializerList node) {
+ processSequential(node, node.getClauses());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(ICASTDesignatedInitializer node) {
+ processSequential(node, node.getDesignators());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(ICPPASTConstructorChainInitializer node) {
+ processSequential(node, node.getMemberInitializerId(), node.getInitializer());
+ return PROCESS_SKIP;
+ }
+
+ public int leave(ICPPASTConstructorInitializer node) {
+ processSequential(node, node.getArguments());
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTTranslationUnit node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ processSequential(node, node.getDeclarations());
+ return PROCESS_SKIP;
+ }
+
+ private void processFunctionCall(IASTFunctionCallExpression node,
+ IASTExpression functionNameExpression, IASTInitializerClause[] arguments) {
+ if (skipNode(node))
+ return;
+ FunctionCallFlowInfo info= createFunctionCallFlowInfo();
+ setFlowInfo(node, info);
+ for (IASTInitializerClause arg : arguments) {
+ info.mergeArgument(getFlowInfo(arg), fFlowContext);
+ }
+ info.mergeReceiver(getFlowInfo(functionNameExpression), fFlowContext);
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowContext.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowContext.java
new file mode 100644
index 00000000000..3c83fc36d72
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowContext.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+
+import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.IVariable;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement;
+
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
+
+public class FlowContext extends LocalVariableIndex {
+ private static class ComputeMode {
+ }
+
+ public static final ComputeMode MERGE = new ComputeMode();
+ public static final ComputeMode ARGUMENTS = new ComputeMode();
+ public static final ComputeMode RETURN_VALUES = new ComputeMode();
+
+ private boolean fConsiderAccessMode;
+ private boolean fLoopReentranceMode;
+ private ComputeMode fComputeMode;
+ private IVariable[] fLocals;
+ private final List<ICPPASTCatchHandler[]> fExceptionStack;
+
+ public FlowContext(IASTFunctionDefinition functionDefinition) {
+ super(functionDefinition);
+ fExceptionStack= new ArrayList<ICPPASTCatchHandler[]>(3);
+ }
+
+ public void setConsiderAccessMode(boolean b) {
+ fConsiderAccessMode= b;
+ }
+
+ public void setComputeMode(ComputeMode mode) {
+ fComputeMode= mode;
+ }
+
+ void setLoopReentranceMode(boolean b) {
+ fLoopReentranceMode= b;
+ }
+
+ int getArrayLength() {
+ return getNumLocalVariables();
+ }
+
+ boolean considerAccessMode() {
+ return fConsiderAccessMode;
+ }
+
+ boolean isLoopReentranceMode() {
+ return fLoopReentranceMode;
+ }
+
+ boolean computeMerge() {
+ return fComputeMode == MERGE;
+ }
+
+ boolean computeArguments() {
+ return fComputeMode == ARGUMENTS;
+ }
+
+ boolean computeReturnValues() {
+ return fComputeMode == RETURN_VALUES;
+ }
+
+ public IVariable getLocalFromIndex(int index) {
+ if (fLocals == null || index > fLocals.length)
+ return null;
+ return fLocals[index];
+ }
+
+ /**
+ * Adds a local variable to the context.
+ * @param localVariable the local variable to manage.
+ */
+ void manageLocal(IVariable localVariable) {
+ int index = getIndexFromLocal(localVariable);
+ if (index >= 0) {
+ if (fLocals == null)
+ fLocals= new IVariable[getNumLocalVariables()];
+ fLocals[index] = localVariable;
+ }
+ }
+
+ //---- Exception handling --------------------------------------------------------
+
+ void pushExceptions(ICPPASTTryBlockStatement node) {
+ ICPPASTCatchHandler[] catchHandlers = node.getCatchHandlers();
+ fExceptionStack.add(catchHandlers);
+ }
+
+ void popExceptions() {
+ Assert.isTrue(fExceptionStack.size() > 0);
+ fExceptionStack.remove(fExceptionStack.size() - 1);
+ }
+
+ boolean isExceptionCaught(IType exceptionType) {
+ for (ICPPASTCatchHandler[] catchHandlers : fExceptionStack) {
+ for (ICPPASTCatchHandler catchHandler : catchHandlers) {
+ if (catchHandler.isCatchAll())
+ return true;
+ IASTDeclaration caughtException= catchHandler.getDeclaration();
+ if (caughtException instanceof IASTSimpleDeclaration) {
+ IASTDeclarator[] declarators = ((IASTSimpleDeclaration) caughtException).getDeclarators();
+ IType caughtType = CPPVisitor.createType(declarators[0]);
+ while (caughtType != null) {
+ // 15.3
+ if (caughtType.isSameType(exceptionType))
+ return true;
+ // TODO(sprigogin): Implement the rest of 15.3 matching logic.
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowInfo.java
new file mode 100644
index 00000000000..6f59e93354c
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowInfo.java
@@ -0,0 +1,428 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Benjamin Muskalla <bmuskalla@eclipsesource.com> - [extract method] missing return type when code can throw exception - https://bugs.eclipse.org/bugs/show_bug.cgi?id=97413
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IVariable;
+
+import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
+
+public abstract class FlowInfo {
+ // Return statement handling.
+ protected static final int NOT_POSSIBLE= 0;
+ protected static final int UNDEFINED= 1;
+ protected static final int NO_RETURN= 2;
+ protected static final int PARTIAL_RETURN= 3;
+ protected static final int VOID_RETURN= 4;
+ protected static final int VALUE_RETURN= 5;
+ protected static final int THROW= 6;
+
+ // Local access handling.
+ public static final int READ= PDOMName.READ_ACCESS; // 1 << 9
+ public static final int WRITE= PDOMName.WRITE_ACCESS; // 1 << 10
+ public static final int UNUSED= 1 << 0;
+ public static final int READ_POTENTIAL= 1 << 1;
+ public static final int WRITE_POTENTIAL= 1 << 2;
+ public static final int UNKNOWN= 1 << 3;
+
+ // Table to merge access modes for condition statements (e.g branch[x] || branch[y]).
+ private static final int[][] ACCESS_MODE_CONDITIONAL_TABLE= {
+ /* UNUSED READ READ_POTENTIAL WRITE WRITE_POTENTIAL UNKNOWN */
+ /* UNUSED */ { UNUSED, READ_POTENTIAL, READ_POTENTIAL, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN },
+ /* READ */ { READ_POTENTIAL, READ, READ_POTENTIAL, UNKNOWN, UNKNOWN, UNKNOWN },
+ /* READ_POTENTIAL */ { READ_POTENTIAL, READ_POTENTIAL, READ_POTENTIAL, UNKNOWN, UNKNOWN, UNKNOWN },
+ /* WRITE */ { WRITE_POTENTIAL, UNKNOWN, UNKNOWN, WRITE, WRITE_POTENTIAL, UNKNOWN },
+ /* WRITE_POTENTIAL */ { WRITE_POTENTIAL, UNKNOWN, UNKNOWN, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN },
+ /* UNKNOWN */ { UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN }
+ };
+
+ // Table to change access mode if there is an open branch statement
+ private static final int[] ACCESS_MODE_OPEN_BRANCH_TABLE= {
+ /* UNUSED READ READ_POTENTIAL WRITE WRITE_POTENTIAL UNKNOWN */
+ UNUSED, READ_POTENTIAL, READ_POTENTIAL, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN
+ };
+
+ // Table to merge return modes for condition statements (y: fReturnKind, x: other.fReturnKind)
+ private static final int[][] RETURN_KIND_CONDITIONAL_TABLE = {
+ /* NOT_POSSIBLE UNDEFINED NO_RETURN PARTIAL_RETURN VOID_RETURN VALUE_RETURN THROW */
+ /* NOT_POSSIBLE */ { NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE },
+ /* UNDEFINED */ { NOT_POSSIBLE, UNDEFINED, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW },
+ /* NO_RETURN */ { NOT_POSSIBLE, NO_RETURN, NO_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, NO_RETURN },
+ /* PARTIAL_RETURN */ { NOT_POSSIBLE, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN },
+ /* VOID_RETURN */ { NOT_POSSIBLE, VOID_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, VOID_RETURN, NOT_POSSIBLE, VOID_RETURN },
+ /* VALUE_RETURN */ { NOT_POSSIBLE, VALUE_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, NOT_POSSIBLE, VALUE_RETURN, VALUE_RETURN },
+ /* THROW */ { NOT_POSSIBLE, THROW, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW }
+ };
+
+ // Table to merge return modes for sequential statements (y: fReturnKind, x: other.fReturnKind)
+ private static final int[][] RETURN_KIND_SEQUENTIAL_TABLE = {
+ /* NOT_POSSIBLE UNDEFINED NO_RETURN PARTIAL_RETURN VOID_RETURN VALUE_RETURN THROW */
+ /* NOT_POSSIBLE */ { NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE },
+ /* UNDEFINED */ { NOT_POSSIBLE, UNDEFINED, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW },
+ /* NO_RETURN */ { NOT_POSSIBLE, NO_RETURN, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW },
+ /* PARTIAL_RETURN */ { NOT_POSSIBLE, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, VALUE_RETURN },
+ /* VOID_RETURN */ { NOT_POSSIBLE, VOID_RETURN, VOID_RETURN, PARTIAL_RETURN, VOID_RETURN, NOT_POSSIBLE, NOT_POSSIBLE },
+ /* VALUE_RETURN */ { NOT_POSSIBLE, VALUE_RETURN, VALUE_RETURN, PARTIAL_RETURN, NOT_POSSIBLE, VALUE_RETURN, NOT_POSSIBLE },
+ /* THROW */ { NOT_POSSIBLE, THROW, THROW, VALUE_RETURN, VOID_RETURN, VALUE_RETURN, THROW }
+ };
+
+ protected static final String UNLABELED = "@unlabeled"; //$NON-NLS-1$
+
+ protected int fReturnKind;
+ protected int[] fAccessModes;
+ protected Set<String> fBranches;
+
+ protected FlowInfo() {
+ this(UNDEFINED);
+ }
+
+ protected FlowInfo(int returnKind) {
+ fReturnKind= returnKind;
+ }
+
+ //---- General Helpers ----------------------------------------------------------
+
+ protected void assignExecutionFlow(FlowInfo right) {
+ fReturnKind= right.fReturnKind;
+ fBranches= right.fBranches;
+ }
+
+ protected void assignAccessMode(FlowInfo right) {
+ fAccessModes= right.fAccessModes;
+ }
+
+ protected void assign(FlowInfo right) {
+ assignExecutionFlow(right);
+ assignAccessMode(right);
+ }
+
+ protected void mergeConditional(FlowInfo info, FlowContext context) {
+ mergeAccessModeConditional(info, context);
+ mergeExecutionFlowConditional(info);
+ }
+
+ protected void mergeSequential(FlowInfo info, FlowContext context) {
+ mergeAccessModeSequential(info, context);
+ mergeExecutionFlowSequential(info);
+ }
+
+ //---- Return Kind ------------------------------------------------------------------
+
+ public void setNoReturn() {
+ fReturnKind= NO_RETURN;
+ }
+
+ public boolean isUndefined() {
+ return fReturnKind == UNDEFINED;
+ }
+
+ public boolean isNoReturn() {
+ return fReturnKind == NO_RETURN;
+ }
+
+ public boolean isPartialReturn() {
+ return fReturnKind == PARTIAL_RETURN;
+ }
+
+ public boolean isVoidReturn() {
+ return fReturnKind == VOID_RETURN;
+ }
+
+ public boolean isValueReturn() {
+ return fReturnKind == VALUE_RETURN;
+ }
+
+ public boolean isThrow() {
+ return fReturnKind == THROW;
+ }
+
+ public boolean isReturn() {
+ return fReturnKind == VOID_RETURN || fReturnKind == VALUE_RETURN;
+ }
+
+ //---- Branches -------------------------------------------------------------------------
+
+ public boolean branches() {
+ return fBranches != null && !fBranches.isEmpty();
+ }
+
+ protected Set<String> getBranches() {
+ return fBranches;
+ }
+
+ protected void removeLabel(IASTName label) {
+ if (fBranches != null) {
+ fBranches.remove(makeString(label));
+ if (fBranches.isEmpty())
+ fBranches= null;
+ }
+ }
+
+ protected static String makeString(IASTName label) {
+ if (label == null) {
+ return UNLABELED;
+ } else {
+ return String.valueOf(label.getSimpleID());
+ }
+ }
+
+ //---- Execution flow -------------------------------------------------------------------
+
+ private void mergeExecutionFlowSequential(FlowInfo otherInfo) {
+ int other= otherInfo.fReturnKind;
+ if (branches() && other == VALUE_RETURN)
+ other= PARTIAL_RETURN;
+ fReturnKind= RETURN_KIND_SEQUENTIAL_TABLE[fReturnKind][other];
+ mergeBranches(otherInfo);
+ }
+
+ private void mergeExecutionFlowConditional(FlowInfo otherInfo) {
+ fReturnKind= RETURN_KIND_CONDITIONAL_TABLE[fReturnKind][otherInfo.fReturnKind];
+ mergeBranches(otherInfo);
+ }
+
+ private void mergeBranches(FlowInfo otherInfo) {
+ fBranches= mergeSets(fBranches, otherInfo.fBranches);
+ }
+
+ private static <T> Set<T> mergeSets(Set<T> thisSet, Set<T> otherSet) {
+ if (otherSet != null) {
+ if (thisSet == null) {
+ thisSet= otherSet;
+ } else {
+ for (T element : otherSet) {
+ thisSet.add(element);
+ }
+ }
+ }
+ return thisSet;
+ }
+
+ //---- Local access handling --------------------------------------------------
+
+ /**
+ * Returns a set of <code>IVariable</code> that conform to the given
+ * access mode <code>mode</code>.
+ *
+ * @param context the flow context object used to compute this flow info
+ * @param mode the access type. Valid values are <code>READ</code>, <code>WRITE</code>,
+ * <code>UNKNOWN</code> and any combination of them.
+ * @return an array of local variable bindings conforming to the given type.
+ */
+ public Set<IVariable> get(FlowContext context, int mode) {
+ if (fAccessModes == null)
+ return Collections.emptySet();
+ Set<IVariable> result= new HashSet<IVariable>(fAccessModes.length);
+ for (int i= 0; i < fAccessModes.length; i++) {
+ int accessMode= fAccessModes[i];
+ if ((accessMode & mode) != 0)
+ result.add(context.getLocalFromIndex(i));
+ }
+ return result;
+ }
+
+ /**
+ * Checks whether the given local variable binding has the given access
+ * mode.
+ *
+ * @param context the flow context used during flow analysis
+ * @param local local variable of interest
+ * @param mode the access mode of the local variable
+ *
+ * @return <code>true</code> if the binding has the given access mode.
+ * <code>False</code> otherwise
+ */
+ public boolean hasAccessMode(FlowContext context, IVariable local, int mode) {
+ boolean unusedMode= (mode & UNUSED) != 0;
+ if (fAccessModes == null && unusedMode)
+ return true;
+ int index= context.getIndexFromLocal(local);
+ if (index == -1)
+ return unusedMode;
+ return (fAccessModes[index] & mode) != 0;
+ }
+
+ /**
+ * Returns the access mode of the local variable identified by the given binding.
+ *
+ * @param context the flow context used during flow analysis
+ * @param local the local variable of interest
+ * @return the access mode of the local variable
+ */
+ public int getAccessMode(FlowContext context, IVariable local) {
+ if (fAccessModes == null)
+ return UNUSED;
+ int index= context.getIndexFromLocal(local);
+ if (index == -1)
+ return UNUSED;
+ return fAccessModes[index];
+ }
+
+ protected int[] getAccessModes() {
+ return fAccessModes;
+ }
+
+ protected void clearAccessMode(IVariable binding, FlowContext context) {
+ if (fAccessModes == null) // All are unused
+ return;
+ int index = context.getIndexFromLocal(binding);
+ if (index >= 0)
+ fAccessModes[index]= UNUSED;
+ }
+
+ protected void mergeAccessModeSequential(FlowInfo otherInfo, FlowContext context) {
+ if (!context.considerAccessMode())
+ return;
+
+ int[] others= otherInfo.fAccessModes;
+ if (others == null) // others are all unused. So nothing to do
+ return;
+
+ // Must not consider return kind since a return statement can't control execution flow
+ // inside a method. It always leaves the method.
+ if (branches()) {
+ for (int i= 0; i < others.length; i++)
+ others[i]= ACCESS_MODE_OPEN_BRANCH_TABLE[getIndex(others[i])];
+ }
+
+ if (fAccessModes == null) { // all current variables are unused
+ fAccessModes= others;
+ return;
+ }
+
+ if (context.computeArguments()) {
+ handleComputeArguments(others);
+ } else if (context.computeReturnValues()) {
+ handleComputeReturnValues(others);
+ } else if (context.computeMerge()) {
+ handleMergeValues(others);
+ }
+ }
+
+ private void handleComputeReturnValues(int[] others) {
+ for (int i= 0; i < fAccessModes.length; i++) {
+ int accessmode= fAccessModes[i];
+ int othermode= others[i];
+ if (accessmode == WRITE)
+ continue;
+ if (accessmode == WRITE_POTENTIAL) {
+ if (othermode == WRITE)
+ fAccessModes[i]= WRITE;
+ continue;
+ }
+
+ if (others[i] != UNUSED)
+ fAccessModes[i]= othermode;
+ }
+ }
+
+ private void handleComputeArguments(int[] others) {
+ for (int i= 0; i < fAccessModes.length; i++) {
+ int accessMode= fAccessModes[i];
+ int otherMode= others[i];
+ if (accessMode == UNUSED) {
+ fAccessModes[i]= otherMode;
+ } else if (accessMode == WRITE_POTENTIAL && (otherMode == READ || otherMode == READ_POTENTIAL)) {
+ // Read always supersedes a potential write even if the read is potential as well
+ // (we have to consider the potential read as an argument then).
+ fAccessModes[i]= otherMode;
+ } else if (accessMode == WRITE_POTENTIAL && otherMode == WRITE) {
+ fAccessModes[i]= WRITE;
+ }
+ }
+ }
+
+ private void handleMergeValues(int[] others) {
+ for (int i= 0; i < fAccessModes.length; i++) {
+ fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE[getIndex(fAccessModes[i])][getIndex(others[i])];
+ }
+ }
+
+ protected void createAccessModeArray(FlowContext context) {
+ fAccessModes= new int[context.getArrayLength()];
+ for (int i= 0; i < fAccessModes.length; i++) {
+ fAccessModes[i]= UNUSED;
+ }
+ }
+
+ protected void mergeAccessModeConditional(FlowInfo otherInfo, FlowContext context) {
+ if (!context.considerAccessMode())
+ return;
+
+ int[] others= otherInfo.fAccessModes;
+ // first access
+ if (fAccessModes == null) {
+ if (others != null) {
+ fAccessModes= others;
+ } else {
+ createAccessModeArray(context);
+ }
+ return;
+ } else {
+ if (others == null) {
+ for (int i= 0; i < fAccessModes.length; i++) {
+ int unused_index= getIndex(UNUSED);
+ fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE[getIndex(fAccessModes[i])][unused_index];
+ }
+ } else {
+ for (int i= 0; i < fAccessModes.length; i++) {
+ fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE[getIndex(fAccessModes[i])][getIndex(others[i])];
+ }
+ }
+ }
+ }
+
+ protected void mergeEmptyCondition(FlowContext context) {
+ if (fReturnKind == VALUE_RETURN || fReturnKind == VOID_RETURN)
+ fReturnKind= PARTIAL_RETURN;
+
+ if (!context.considerAccessMode())
+ return;
+
+ if (fAccessModes == null) {
+ createAccessModeArray(context);
+ return;
+ }
+
+ int unused_index= getIndex(UNUSED);
+ for (int i= 0; i < fAccessModes.length; i++) {
+ fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE[getIndex(fAccessModes[i])][unused_index];
+ }
+ }
+
+ private static int getIndex(int accessMode) {
+ // Fast log function
+ switch (accessMode) {
+ case UNUSED:
+ return 0;
+ case READ:
+ return 1;
+ case READ_POTENTIAL:
+ return 2;
+ case WRITE:
+ case READ | WRITE:
+ return 3;
+ case WRITE_POTENTIAL:
+ return 4;
+ case UNKNOWN:
+ return 5;
+ }
+ return -1;
+ }
+}
+
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ForFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ForFlowInfo.java
new file mode 100644
index 00000000000..e97bc87b3f5
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ForFlowInfo.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class ForFlowInfo extends FlowInfo {
+
+ public void mergeInitializer(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeAccessModeSequential(info, context);
+ }
+
+ public void mergeCondition(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeAccessModeSequential(info, context);
+ }
+
+ public void mergeIncrement(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ info.mergeEmptyCondition(context);
+ mergeAccessModeSequential(info, context);
+ }
+
+ public void mergeAction(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ info.mergeEmptyCondition(context);
+
+ mergeSequential(info, context);
+ }
+}
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FunctionCallFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FunctionCallFlowInfo.java
new file mode 100644
index 00000000000..d55c4cc40c1
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FunctionCallFlowInfo.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class FunctionCallFlowInfo extends FlowInfo {
+
+ public FunctionCallFlowInfo() {
+ super(NO_RETURN);
+ }
+
+ public void mergeArgument(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeSequential(info, context);
+ }
+
+ public void mergeReceiver(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeSequential(info, context);
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/GenericConditionalFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/GenericConditionalFlowInfo.java
new file mode 100644
index 00000000000..7cc2a6c76aa
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/GenericConditionalFlowInfo.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class GenericConditionalFlowInfo extends FlowInfo {
+
+ public GenericConditionalFlowInfo() {
+ super(UNDEFINED);
+ }
+
+ public void merge(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ mergeConditional(info, context);
+ }
+
+ public void mergeAccessMode(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ mergeAccessModeConditional(info, context);
+ }
+}
+
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/GenericSequentialFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/GenericSequentialFlowInfo.java
new file mode 100644
index 00000000000..2d219c94d4c
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/GenericSequentialFlowInfo.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class GenericSequentialFlowInfo extends FlowInfo {
+
+ public GenericSequentialFlowInfo() {
+ super(NO_RETURN);
+ }
+
+ public void merge(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeSequential(info, context);
+ }
+
+ public void mergeAccessMode(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeAccessModeSequential(info, context);
+ }
+}
+
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/IfFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/IfFlowInfo.java
new file mode 100644
index 00000000000..ffeaa595197
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/IfFlowInfo.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class IfFlowInfo extends FlowInfo {
+
+ public void mergeCondition(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeAccessModeSequential(info, context);
+ }
+
+ public void merge(FlowInfo thenPart, FlowInfo elsePart, FlowContext context) {
+ if (thenPart == null && elsePart == null)
+ return;
+
+ GenericConditionalFlowInfo cond= new GenericConditionalFlowInfo();
+ if (thenPart != null)
+ cond.merge(thenPart, context);
+
+ if (elsePart != null)
+ cond.merge(elsePart, context);
+
+ if (thenPart == null || elsePart == null)
+ cond.mergeEmptyCondition(context);
+
+ mergeSequential(cond, context);
+ }
+}
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/InOutFlowAnalyzer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/InOutFlowAnalyzer.java
new file mode 100644
index 00000000000..42a353bf092
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/InOutFlowAnalyzer.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
+import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
+import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTForStatement;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
+import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTStatement;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.IField;
+import org.eclipse.cdt.core.dom.ast.IVariable;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
+import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator;
+
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
+
+public class InOutFlowAnalyzer extends FlowAnalyzer {
+
+ public InOutFlowAnalyzer(FlowContext context) {
+ super(context);
+ }
+
+ public FlowInfo perform(IASTNode[] selectedNodes) {
+ FlowContext context= getFlowContext();
+ GenericSequentialFlowInfo result= createSequential();
+ for (int i= 0; i < selectedNodes.length; i++) {
+ IASTNode node= selectedNodes[i];
+ node.accept(this);
+ result.merge(getFlowInfo(node), context);
+ }
+ return result;
+ }
+
+ @Override
+ protected boolean traverseNode(IASTNode node) {
+ // We are only traversing the selected nodes.
+ return true;
+ }
+
+ @Override
+ protected boolean createReturnFlowInfo(IASTReturnStatement node) {
+ // We are only traversing selected nodes.
+ return true;
+ }
+
+ @Override
+ public int leave(IASTCompoundStatement node) {
+ super.leave(node);
+ clearAccessMode(accessFlowInfo(node), node.getStatements());
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(ICPPASTCatchHandler node) {
+ super.leave(node);
+ clearAccessMode(accessFlowInfo(node), node.getDeclaration());
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTForStatement node) {
+ super.leave(node);
+ clearAccessMode(accessFlowInfo(node), node.getInitializerStatement());
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(ICPPASTRangeBasedForStatement node) {
+ super.leave(node);
+ clearAccessMode(accessFlowInfo(node), node.getDeclaration());
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTFunctionDefinition node) {
+ super.leave(node);
+ FlowInfo info= accessFlowInfo(node);
+ IASTFunctionDeclarator declarator = node.getDeclarator();
+ if (declarator instanceof IASTStandardFunctionDeclarator) {
+ for (IASTParameterDeclaration param : ((IASTStandardFunctionDeclarator) declarator).getParameters()) {
+ clearAccessMode(info, param.getDeclarator());
+ }
+ } else if (declarator instanceof ICASTKnRFunctionDeclarator) {
+ for (IASTDeclaration param : ((ICASTKnRFunctionDeclarator) declarator).getParameterDeclarations()) {
+ clearAccessMode(info, param);
+ }
+ }
+ return PROCESS_SKIP;
+ }
+
+ private void clearAccessMode(FlowInfo info, IASTStatement[] statements) {
+ if (statements == null || statements.length == 0 || info == null)
+ return;
+ for (IASTStatement statement : statements) {
+ clearAccessMode(info, statement);
+ }
+ }
+
+ private void clearAccessMode(FlowInfo info, IASTStatement statement) {
+ if (statement instanceof IASTDeclarationStatement) {
+ IASTDeclaration declaration = ((IASTDeclarationStatement) statement).getDeclaration();
+ clearAccessMode(info, declaration);
+ }
+ }
+
+ private void clearAccessMode(FlowInfo info, IASTDeclaration declaration) {
+ if (declaration instanceof IASTSimpleDeclaration) {
+ IASTDeclarator[] declarators = ((IASTSimpleDeclaration) declaration).getDeclarators();
+ for (IASTDeclarator declarator : declarators) {
+ clearAccessMode(info, declarator);
+ }
+ }
+ }
+
+ private void clearAccessMode(FlowInfo info, IASTDeclarator declarator) {
+ declarator = CPPVisitor.findInnermostDeclarator(declarator);
+ IASTName name = declarator.getName();
+ IBinding binding= name.resolveBinding();
+ if (binding instanceof IVariable && !(binding instanceof IField))
+ info.clearAccessMode((IVariable) binding, fFlowContext);
+ }
+}
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/InputFlowAnalyzer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/InputFlowAnalyzer.java
new file mode 100644
index 00000000000..885239e1e28
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/InputFlowAnalyzer.java
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Dmitry Stalnov (dstalnov@fusionone.com) - contributed fix for
+ * o inline call that is used in a field initializer
+ * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38137)
+ * Benjamin Muskalla <bmuskalla@eclipsesource.com> - [extract method] Missing return value,
+ * while extracting code out of a loop - https://bugs.eclipse.org/bugs/show_bug.cgi?id=213519
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.text.IRegion;
+
+import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
+import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
+import org.eclipse.cdt.core.dom.ast.IASTExpression;
+import org.eclipse.cdt.core.dom.ast.IASTForStatement;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
+import org.eclipse.cdt.core.dom.ast.IASTStatement;
+import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
+import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
+
+import org.eclipse.cdt.internal.corext.util.ASTNodes;
+
+public class InputFlowAnalyzer extends FlowAnalyzer {
+
+ private static class LoopReentranceVisitor extends FlowAnalyzer {
+ private Selection fSelection;
+ private IASTNode fLoopNode;
+
+ public LoopReentranceVisitor(FlowContext context, Selection selection, IASTNode loopNode) {
+ super(context);
+ fSelection= selection;
+ fLoopNode= loopNode;
+ }
+
+ @Override
+ protected boolean traverseNode(IASTNode node) {
+ return true; // end <= fSelection.end || fSelection.enclosedBy(start, end);
+ }
+
+ @Override
+ protected boolean createReturnFlowInfo(IASTReturnStatement node) {
+ // Make sure that the whole return statement is selected or located before the selection.
+ return ASTNodes.endOffset(node) <= fSelection.getEnd();
+ }
+
+ protected IASTNode getLoopNode() {
+ return fLoopNode;
+ }
+
+ public void process(IASTNode node) {
+ try {
+ fFlowContext.setLoopReentranceMode(true);
+ node.accept(this);
+ } finally {
+ fFlowContext.setLoopReentranceMode(false);
+ }
+ }
+
+ @Override
+ public int leave(IASTDoStatement node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ DoWhileFlowInfo info= createDoWhile();
+ setFlowInfo(node, info);
+ info.mergeAction(getFlowInfo(node.getBody()), fFlowContext);
+ // No need to merge the condition. It was already considered by the InputFlowAnalyzer.
+ info.removeLabel(null);
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(ICPPASTRangeBasedForStatement node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ FlowInfo paramInfo= getFlowInfo(node.getDeclaration());
+ FlowInfo expressionInfo= getFlowInfo(node.getInitializerClause());
+ FlowInfo actionInfo= getFlowInfo(node.getBody());
+ RangeBasedForFlowInfo forInfo= createEnhancedFor();
+ setFlowInfo(node, forInfo);
+ // If the for statement is the outermost loop then we only have to consider
+ // the action. The parameter and expression are only evaluated once.
+ if (node == fLoopNode) {
+ forInfo.mergeAction(actionInfo, fFlowContext);
+ } else {
+ // Inner for loops are evaluated in the sequence expression, parameter,
+ // action.
+ forInfo.mergeInitializerClause(expressionInfo, fFlowContext);
+ forInfo.mergeDeclaration(paramInfo, fFlowContext);
+ forInfo.mergeAction(actionInfo, fFlowContext);
+ }
+ forInfo.removeLabel(null);
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTForStatement node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ FlowInfo initInfo= createSequential(node.getInitializerStatement());
+ FlowInfo conditionInfo= getFlowInfo(node.getConditionExpression());
+ FlowInfo incrementInfo= createSequential(node.getIterationExpression());
+ FlowInfo actionInfo= getFlowInfo(node.getBody());
+ ForFlowInfo forInfo= createFor();
+ setFlowInfo(node, forInfo);
+ // The for statement is the outermost loop. In this case we only have
+ // to consider the increment, condition and action.
+ if (node == fLoopNode) {
+ forInfo.mergeIncrement(incrementInfo, fFlowContext);
+ forInfo.mergeCondition(conditionInfo, fFlowContext);
+ forInfo.mergeAction(actionInfo, fFlowContext);
+ } else {
+ // We have to merge two different cases. One if we reenter the for statement
+ // immediatelly (that means we have to consider increments, condition and action)
+ // and the other case if we reenter the for in the next loop of
+ // the outer loop. Then we have to consider initializations, condtion and action.
+ // For a conditional flow info that means:
+ // (initializations | increments) & condition & action.
+ GenericConditionalFlowInfo initIncr= new GenericConditionalFlowInfo();
+ initIncr.merge(initInfo, fFlowContext);
+ initIncr.merge(incrementInfo, fFlowContext);
+ forInfo.mergeAccessModeSequential(initIncr, fFlowContext);
+ forInfo.mergeCondition(conditionInfo, fFlowContext);
+ forInfo.mergeAction(actionInfo, fFlowContext);
+ }
+ forInfo.removeLabel(null);
+ return PROCESS_SKIP;
+ }
+ }
+
+ private Selection fSelection;
+ private boolean fDoLoopReentrance;
+ private LoopReentranceVisitor fLoopReentranceVisitor;
+
+ public InputFlowAnalyzer(FlowContext context, Selection selection, boolean doLoopReentrance) {
+ super(context);
+ fSelection= selection;
+ Assert.isNotNull(fSelection);
+ fDoLoopReentrance= doLoopReentrance;
+ }
+
+ public FlowInfo perform(IASTFunctionDefinition node) {
+ node.accept(this);
+ return getFlowInfo(node);
+ }
+
+ @Override
+ protected boolean traverseNode(IASTNode node) {
+ return ASTNodes.endOffset(node) > fSelection.getEnd();
+ }
+
+ @Override
+ protected boolean createReturnFlowInfo(IASTReturnStatement node) {
+ // Make sure that the whole return statement is located after the selection.
+ // There can be cases like return i + [x + 10] * 10; In this case we must not create
+ // a return info node.
+ return ASTNodes.offset(node) >= fSelection.getEnd();
+ }
+
+ @Override
+ public int visit(IASTDoStatement node) {
+ createLoopReentranceVisitor(node);
+ return super.visit(node);
+ }
+
+ @Override
+ public int visit(ICPPASTRangeBasedForStatement node) {
+ createLoopReentranceVisitor(node);
+ return super.visit(node);
+ }
+
+ @Override
+ public int visit(IASTForStatement node) {
+ createLoopReentranceVisitor(node);
+ return super.visit(node);
+ }
+
+ @Override
+ public int visit(IASTWhileStatement node) {
+ createLoopReentranceVisitor(node);
+ return super.visit(node);
+ }
+
+ private void createLoopReentranceVisitor(IASTNode node) {
+ if (fLoopReentranceVisitor == null && fDoLoopReentrance && fSelection.coveredBy(node)) {
+ fLoopReentranceVisitor= new LoopReentranceVisitor(fFlowContext, fSelection, node);
+ }
+ }
+
+ @Override
+ public int leave(IASTConditionalExpression node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ IASTExpression thenPart= node.getPositiveResultExpression();
+ IASTExpression elsePart= node.getNegativeResultExpression();
+ if ((thenPart != null && fSelection.coveredBy(thenPart)) ||
+ (elsePart != null && fSelection.coveredBy(elsePart))) {
+ GenericSequentialFlowInfo info= createSequential();
+ setFlowInfo(node, info);
+ endVisitConditional(info, node.getLogicalConditionExpression(), new IASTNode[] { thenPart, elsePart });
+ return PROCESS_SKIP;
+ }
+ return super.leave(node);
+ }
+
+ @Override
+ public int leave(IASTDoStatement node) {
+ super.leave(node);
+ handleLoopReentrance(node);
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTIfStatement node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ IASTStatement thenPart= node.getThenClause();
+ IASTStatement elsePart= node.getElseClause();
+ if ((thenPart != null && fSelection.coveredBy(thenPart)) ||
+ (elsePart != null && fSelection.coveredBy(elsePart))) {
+ GenericSequentialFlowInfo info= createSequential();
+ setFlowInfo(node, info);
+ endVisitConditional(info, node.getConditionExpression(), new IASTNode[] { thenPart, elsePart });
+ return PROCESS_SKIP;
+ }
+ return super.leave(node);
+ }
+
+ @Override
+ public int leave(ICPPASTRangeBasedForStatement node) {
+ super.leave(node);
+ handleLoopReentrance(node);
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTForStatement node) {
+ super.leave(node);
+ handleLoopReentrance(node);
+ return PROCESS_SKIP;
+ }
+
+ @Override
+ public int leave(IASTSwitchStatement node) {
+ if (skipNode(node))
+ return PROCESS_SKIP;
+ SwitchData data= createSwitchData(node);
+ IRegion[] ranges= data.getRanges();
+ for (int i= 0; i < ranges.length; i++) {
+ IRegion range= ranges[i];
+ if (fSelection.coveredBy(range)) {
+ GenericSequentialFlowInfo info= createSequential();
+ setFlowInfo(node, info);
+ info.merge(getFlowInfo(node.getControllerExpression()), fFlowContext);
+ info.merge(data.getInfo(i), fFlowContext);
+ info.removeLabel(null);
+ return PROCESS_SKIP;
+ }
+ }
+ return super.leave(node, data);
+ }
+
+ @Override
+ public int leave(IASTWhileStatement node) {
+ super.leave(node);
+ handleLoopReentrance(node);
+ return PROCESS_SKIP;
+ }
+
+ private void endVisitConditional(GenericSequentialFlowInfo info, IASTNode condition, IASTNode[] branches) {
+ info.merge(getFlowInfo(condition), fFlowContext);
+ for (int i= 0; i < branches.length; i++) {
+ IASTNode branch= branches[i];
+ if (branch != null && fSelection.coveredBy(branch)) {
+ info.merge(getFlowInfo(branch), fFlowContext);
+ break;
+ }
+ }
+ }
+
+ private void handleLoopReentrance(IASTNode node) {
+ if (fLoopReentranceVisitor == null || fLoopReentranceVisitor.getLoopNode() != node)
+ return;
+
+ fLoopReentranceVisitor.process(node);
+ GenericSequentialFlowInfo info= createSequential();
+ info.merge(getFlowInfo(node), fFlowContext);
+ info.merge(fLoopReentranceVisitor.getFlowInfo(node), fFlowContext);
+ setFlowInfo(node, info);
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/LocalFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/LocalFlowInfo.java
new file mode 100644
index 00000000000..8bbbb4945c6
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/LocalFlowInfo.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+import org.eclipse.cdt.core.dom.ast.IVariable;
+
+class LocalFlowInfo extends FlowInfo {
+ private final int fVariableIndex;
+
+ public LocalFlowInfo(IVariable binding, int localAccessMode, FlowContext context) {
+ super(NO_RETURN);
+ fVariableIndex= context.getIndexFromLocal(binding);
+ if (fVariableIndex < 0)
+ throw new IllegalStateException("Invalid local variable \"" + binding.getName() + "\" for the context."); //$NON-NLS-1$ //$NON-NLS-2$
+ if (context.considerAccessMode()) {
+ createAccessModeArray(context);
+ context.manageLocal(binding);
+ fAccessModes[fVariableIndex]= localAccessMode;
+ }
+ }
+
+ public LocalFlowInfo(LocalFlowInfo info, int localAccessMode, FlowContext context) {
+ super(NO_RETURN);
+ fVariableIndex= info.fVariableIndex;
+ if (context.considerAccessMode()) {
+ createAccessModeArray(context);
+ fAccessModes[fVariableIndex]= localAccessMode;
+ }
+ }
+
+ public void setWriteAccess(FlowContext context) {
+ if (context.considerAccessMode()) {
+ fAccessModes[fVariableIndex]= FlowInfo.WRITE;
+ }
+ }
+}
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/LocalVariableIndex.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/LocalVariableIndex.java
new file mode 100644
index 00000000000..c33ea8ed331
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/LocalVariableIndex.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Google, Inc 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sergey Prigogin (Google) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.core.dom.ast.ASTVisitor;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.IField;
+import org.eclipse.cdt.core.dom.ast.IVariable;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
+
+/**
+ * Index of local variables inside a function. Each variable is assigned an integer index in normal
+ * code reading order. A variable with a smaller index is declared before a variable with a larger
+ * one.
+ */
+public class LocalVariableIndex {
+ private final Map<IVariable, Integer> variableMap = new HashMap<IVariable, Integer>();
+
+ public LocalVariableIndex(IASTFunctionDefinition functionDefinition) {
+ functionDefinition.accept(new ASTVisitor() {
+ {
+ shouldVisitNames = true;
+ }
+
+ @Override
+ public int visit(IASTName name) {
+ if (name instanceof ICPPASTQualifiedName || name.isQualified() || !name.isDeclaration()) {
+ return PROCESS_CONTINUE;
+ }
+
+ IBinding binding = name.resolveBinding();
+ if (binding instanceof IVariable && !(binding instanceof IField)) {
+ IVariable variable = (IVariable) binding;
+ if (!variableMap.containsKey(variable)) {
+ variableMap.put(variable, variableMap.size());
+ }
+ }
+ return PROCESS_CONTINUE;
+ }
+ });
+ }
+
+ /**
+ * Returns the number of local variables in the index.
+ */
+ public int getNumLocalVariables() {
+ return variableMap.size();
+ }
+
+ /**
+ * Returns the index for the given local variable.
+ * @param variable the local variable
+ * @return the index of the variable, or -1 if the variable in not contained in the index.
+ */
+ public int getIndexFromLocal(IVariable variable) {
+ Integer index = variableMap.get(variable);
+ return index != null ? index.intValue() : -1;
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/RangeBasedForFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/RangeBasedForFlowInfo.java
new file mode 100644
index 00000000000..fde3c64000b
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/RangeBasedForFlowInfo.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class RangeBasedForFlowInfo extends FlowInfo {
+
+ public void mergeDeclaration(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeAccessModeSequential(info, context);
+ }
+
+ public void mergeInitializerClause(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeAccessModeSequential(info, context);
+ }
+
+ public void mergeAction(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ info.mergeEmptyCondition(context);
+ mergeSequential(info, context);
+ }
+}
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ReturnFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ReturnFlowInfo.java
new file mode 100644
index 00000000000..323d5703972
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ReturnFlowInfo.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+import org.eclipse.cdt.core.dom.ast.IASTExpression;
+import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
+
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
+
+class ReturnFlowInfo extends FlowInfo {
+
+ public ReturnFlowInfo(IASTReturnStatement node) {
+ super(getReturnFlag(node));
+ }
+
+ public void merge(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ assignAccessMode(info);
+ }
+
+ private static int getReturnFlag(IASTReturnStatement node) {
+ IASTExpression expression= node.getReturnValue();
+ if (expression == null || SemanticUtil.isVoidType(expression.getExpressionType()))
+ return VOID_RETURN;
+ return VALUE_RETURN;
+ }
+}
+
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/Selection.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/Selection.java
new file mode 100644
index 00000000000..cc9d2b9bea1
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/Selection.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.text.IRegion;
+
+import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+
+public class Selection {
+ /** Flag indicating that the AST node somehow intersects with the selection. */
+ public static final int INTERSECTS= 0;
+
+ /** Flag that indicates that an AST node appears before the selected nodes. */
+ public static final int BEFORE= 1;
+
+ /** Flag indicating that an AST node is covered by the selection. */
+ public static final int SELECTED= 2;
+
+ /** Flag indicating that an AST nodes appears after the selected nodes. */
+ public static final int AFTER= 3;
+
+ private int fStart;
+ private int fLength;
+ private int fEnd;
+
+ protected Selection() {
+ }
+
+ /**
+ * Creates a new selection from the given start and length.
+ *
+ * @param start the start offset of the selection (inclusive)
+ * @param length the length of the selection
+ * @return the created selection object
+ */
+ public static Selection createFromStartLength(int start, int length) {
+ Assert.isTrue(start >= 0 && length >= 0);
+ Selection result= new Selection();
+ result.fStart= start;
+ result.fLength= length;
+ result.fEnd= start + length;
+ return result;
+ }
+
+ /**
+ * Creates a new selection from the given start and end.
+ *
+ * @param start the start offset of the selection (inclusive)
+ * @param end the end offset of the selection (exclusive)
+ * @return the created selection object
+ */
+ public static Selection createFromStartEnd(int start, int end) {
+ Assert.isTrue(start >= 0 && end >= start);
+ Selection result= new Selection();
+ result.fStart= start;
+ result.fLength= end - start;
+ result.fEnd= result.fStart + result.fLength;
+ return result;
+ }
+
+ public int getOffset() {
+ return fStart;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getEnd() {
+ return fEnd;
+ }
+
+ /**
+ * Returns the selection mode of the given AST node regarding this selection. Possible
+ * values are <code>INTERSECTS</code>, <code>BEFORE</code>, <code>SELECTED</code>, and
+ * <code>AFTER</code>.
+ *
+ * @param node the node to return the visit mode for
+ *
+ * @return the selection mode of the given AST node regarding this selection
+ * @see #INTERSECTS
+ * @see #BEFORE
+ * @see #SELECTED
+ * @see #AFTER
+ */
+ public int getVisitSelectionMode(IASTNode node) {
+ IASTFileLocation location = node.getFileLocation();
+ int nodeStart= location.getNodeOffset();
+ int nodeEnd= nodeStart + location.getNodeLength();
+ if (nodeEnd <= fStart) {
+ return BEFORE;
+ } else if (covers(node)) {
+ return SELECTED;
+ } else if (fEnd <= nodeStart) {
+ return AFTER;
+ }
+ return INTERSECTS;
+ }
+
+ public int getEndVisitSelectionMode(IASTNode node) {
+ IASTFileLocation location = node.getFileLocation();
+ int nodeStart= location.getNodeOffset();
+ int nodeEnd= nodeStart + location.getNodeLength();
+ if (nodeEnd <= fStart) {
+ return BEFORE;
+ } else if (covers(node)) {
+ return SELECTED;
+ } else if (nodeEnd >= fEnd) {
+ return AFTER;
+ }
+ return INTERSECTS;
+ }
+
+ // cover* methods do a closed interval check.
+
+ public boolean covers(int position) {
+ return fStart <= position && position < fStart + fLength;
+ }
+
+ public boolean covers(IASTNode node) {
+ IASTFileLocation location = node.getFileLocation();
+ int nodeStart= location.getNodeOffset();
+ return fStart <= nodeStart && nodeStart + location.getNodeLength() <= fEnd;
+ }
+
+ public boolean coveredBy(IASTNode node) {
+ IASTFileLocation location = node.getFileLocation();
+ int nodeStart= location.getNodeOffset();
+ return nodeStart <= fStart && fEnd <= nodeStart + location.getNodeLength();
+ }
+
+ public boolean coveredBy(IRegion region) {
+ int regionStart= region.getOffset();
+ return regionStart <= fStart && fEnd <= regionStart + region.getLength();
+ }
+
+ public boolean endsIn(IASTNode node) {
+ IASTFileLocation location = node.getFileLocation();
+ int nodeStart= location.getNodeOffset();
+ return nodeStart < fEnd && fEnd < nodeStart + location.getNodeLength();
+ }
+
+ public boolean liesOutside(IASTNode node) {
+ IASTFileLocation location = node.getFileLocation();
+ int nodeStart= location.getNodeOffset();
+ return fEnd < nodeStart || nodeStart + location.getNodeLength() < fStart;
+ }
+
+ @Override
+ public String toString() {
+ return "<start == " + fStart + ", length == " + fLength + "/>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/SwitchFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/SwitchFlowInfo.java
new file mode 100644
index 00000000000..be0a50f7b31
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/SwitchFlowInfo.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class SwitchFlowInfo extends FlowInfo {
+ private GenericConditionalFlowInfo fCases;
+ private boolean fHasNullCaseInfo;
+
+ public SwitchFlowInfo() {
+ fCases= new GenericConditionalFlowInfo();
+ }
+
+ public void mergeTest(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+ mergeSequential(info, context);
+ }
+
+ public void mergeCase(FlowInfo info, FlowContext context) {
+ if (info == null) {
+ fHasNullCaseInfo= true;
+ return;
+ }
+ fCases.mergeConditional(info, context);
+ }
+
+ public void mergeDefault(boolean defaultCaseExists, FlowContext context) {
+ if (!defaultCaseExists || fHasNullCaseInfo)
+ fCases.mergeEmptyCondition(context);
+ mergeSequential(fCases, context);
+ }
+}
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ThrowFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ThrowFlowInfo.java
new file mode 100644
index 00000000000..4b20b43efa9
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/ThrowFlowInfo.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class ThrowFlowInfo extends FlowInfo {
+
+ public ThrowFlowInfo() {
+ super(THROW);
+ }
+
+ public void merge(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ assignAccessMode(info);
+ }
+}
+
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/TryFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/TryFlowInfo.java
new file mode 100644
index 00000000000..93ca4b12921
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/TryFlowInfo.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class TryFlowInfo extends FlowInfo {
+
+ public TryFlowInfo() {
+ super();
+ }
+
+ public void mergeTry(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ assign(info);
+ }
+
+ public void mergeCatch(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ mergeConditional(info, context);
+ }
+
+ public void mergeFinally(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ mergeSequential(info, context);
+ }
+}
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/WhileFlowInfo.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/WhileFlowInfo.java
new file mode 100644
index 00000000000..f6b4030ae7a
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/WhileFlowInfo.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.refactoring.code.flow;
+
+class WhileFlowInfo extends FlowInfo {
+
+ public void mergeCondition(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ mergeAccessModeSequential(info, context);
+ }
+
+ public void mergeAction(FlowInfo info, FlowContext context) {
+ if (info == null)
+ return;
+
+ info.mergeEmptyCondition(context);
+
+ mergeSequential(info, context);
+ }
+}
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/util/ASTNodes.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/util/ASTNodes.java
new file mode 100644
index 00000000000..360ddfc0358
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/util/ASTNodes.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Google, Inc 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sergey Prigogin (Google) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.corext.util;
+
+import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+
+/**
+ * Collection of helper methods for common operations on AST nodes.
+ */
+public class ASTNodes {
+
+ // Not instantiatable.
+ private ASTNodes() {
+ }
+
+ /**
+ * Returns the offset of an AST node.
+ */
+ public static int offset(IASTNode node) {
+ return node.getFileLocation().getNodeOffset();
+ }
+
+ /**
+ * Returns the exclusive end offset of an AST node.
+ */
+ public static int endOffset(IASTNode node) {
+ IASTFileLocation location = node.getFileLocation();
+ return location.getNodeOffset() + location.getNodeLength();
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NameInformation.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NameInformation.java
index cfb7ec04c2e..8859680deed 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NameInformation.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NameInformation.java
@@ -46,10 +46,7 @@ public class NameInformation {
private final IASTName name;
private IASTName declarationName;
- private final List<IASTName> references;
- private final List<IASTName> referencesBeforeSelection;
private final List<IASTName> referencesInSelection;
- private final List<IASTName> referencesAfterSelection;
private boolean isOutput;
private boolean mustBeReturnValue;
private boolean isWriteAccess;
@@ -65,10 +62,7 @@ public class NameInformation {
public NameInformation(IASTName name) {
this.name = name;
this.newName = String.valueOf(name.getSimpleID());
- references = new ArrayList<IASTName>();
- referencesBeforeSelection = new ArrayList<IASTName>();
referencesInSelection = new ArrayList<IASTName>();
- referencesAfterSelection = new ArrayList<IASTName>();
}
public static NameInformation createInfoForAddedParameter(String type, String name,
@@ -205,14 +199,9 @@ public class NameInformation {
}
void addReference(IASTName name, int startOffset, int endOffset) {
- references.add(name);
int nodeOffset = name.getFileLocation().getNodeOffset();
- if (nodeOffset >= endOffset) {
- referencesAfterSelection.add(name);
- } else if (nodeOffset >= startOffset) {
+ if (nodeOffset >= startOffset && nodeOffset < endOffset) {
referencesInSelection.add(name);
- } else {
- referencesBeforeSelection.add(name);
}
}
@@ -244,22 +233,10 @@ public class NameInformation {
return writer.toString();
}
- public List<IASTName> getReferencesBeforeSelection() {
- return referencesBeforeSelection;
- }
-
public List<IASTName> getReferencesInSelection() {
return referencesInSelection;
}
- public List<IASTName> getReferencesAfterSelection() {
- return referencesAfterSelection;
- }
-
- public boolean isReferencedAfterSelection() {
- return !referencesAfterSelection.isEmpty();
- }
-
public IASTParameterDeclaration getParameterDeclaration(INodeFactory nodeFactory) {
return getParameterDeclaration(nodeFactory, newName);
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NodeContainer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NodeContainer.java
index 38ce30f0dd0..00f9ae4e6f9 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NodeContainer.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NodeContainer.java
@@ -28,6 +28,7 @@ import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
@@ -44,7 +45,13 @@ import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.PreferenceConstants;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVariableReadWriteFlags;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
+import org.eclipse.cdt.internal.corext.refactoring.code.flow.FlowContext;
+import org.eclipse.cdt.internal.corext.refactoring.code.flow.FlowInfo;
+import org.eclipse.cdt.internal.corext.refactoring.code.flow.InputFlowAnalyzer;
+import org.eclipse.cdt.internal.corext.refactoring.code.flow.Selection;
+import org.eclipse.cdt.internal.corext.util.ASTNodes;
public class NodeContainer {
private final List<IASTNode> nodes;
@@ -152,6 +159,8 @@ public class NodeContainer {
if (interfaceNames == null) {
findAllNames();
+ Set<IVariable> externalReads = getVariablesReadOutside();
+
Set<IASTName> declarations = new HashSet<IASTName>();
interfaceNames = new ArrayList<NameInformation>();
@@ -159,7 +168,7 @@ public class NodeContainer {
IASTName declarationName = nameInfo.getDeclarationName();
if (declarations.add(declarationName)) {
if (isDeclaredInSelection(nameInfo)) {
- if (nameInfo.isReferencedAfterSelection()) {
+ if (externalReads.contains(nameInfo.getName().resolveBinding())) {
nameInfo.setMustBeReturnValue(true);
interfaceNames.add(nameInfo);
}
@@ -175,7 +184,8 @@ public class NodeContainer {
}
}
}
- if (nameInfo.isWriteAccess() && nameInfo.isReferencedAfterSelection()) {
+ if (nameInfo.isWriteAccess() &&
+ externalReads.contains(nameInfo.getName().resolveBinding())) {
nameInfo.setOutput(true);
}
}
@@ -188,6 +198,25 @@ public class NodeContainer {
return interfaceNames;
}
+ private Set<IVariable> getVariablesReadOutside() {
+ if (nodes.isEmpty())
+ return Collections.emptySet();
+
+ IASTNode firstNode = nodes.get(0);
+ IASTFunctionDefinition enclosingFunction =
+ CPPVisitor.findAncestorWithType(firstNode, IASTFunctionDefinition.class);
+ FlowContext flowContext= new FlowContext(enclosingFunction);
+ flowContext.setConsiderAccessMode(true);
+ flowContext.setComputeMode(FlowContext.ARGUMENTS);
+ // Compute a selection that exactly covers the selected nodes
+ Selection selection= Selection.createFromStartEnd(ASTNodes.offset(firstNode),
+ ASTNodes.endOffset(nodes.get(nodes.size() - 1)));
+
+ InputFlowAnalyzer analyzer = new InputFlowAnalyzer(flowContext, selection, true);
+ FlowInfo argInfo= analyzer.perform(enclosingFunction);
+ return argInfo.get(flowContext, FlowInfo.READ | FlowInfo.READ_POTENTIAL | FlowInfo.UNKNOWN);
+ }
+
public static boolean hasReferenceOperator(IASTDeclarator declarator) {
IASTPointerOperator[] operators = declarator.getPointerOperators();
return operators.length != 0 && operators[operators.length - 1] instanceof ICPPASTReferenceOperator;
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/StatementExtractor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/StatementExtractor.java
index b6da4787615..88aa42d6b14 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/StatementExtractor.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/StatementExtractor.java
@@ -58,7 +58,8 @@ public class StatementExtractor extends FunctionExtractor {
NameInformation returnVariable) {
if (returnVariable != null) {
IASTNode decl = ASTHelper.getDeclarationForNode(returnVariable.getDeclarationName());
- return ASTHelper.getDeclarationSpecifier(decl).copy(CopyStyle.withLocations);
+ IASTDeclSpecifier declSpec = ASTHelper.getDeclarationSpecifier(decl);
+ return declSpec != null ? declSpec.copy(CopyStyle.withLocations) : null;
}
IASTSimpleDeclSpecifier declSpec = new CPPASTSimpleDeclSpecifier();
declSpec.setType(IASTSimpleDeclSpecifier.t_void);

Back to the top