summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2018-07-19 01:48:34 (GMT)
committerGitHub <noreply@github.com>2018-07-19 01:48:34 (GMT)
commit2d7e4871b1bd5bab501cdbb3d0373b1617d0ebfa (patch)
tree685a6fa82d7e22230f1bc99b56a830dd128833db
parent0b9e3131647ba6a685f75e8c51fde78de2a133e8 (diff)
parent1d947b99536bdaf906cabc634d88a5fd99c521a2 (diff)
downloadSCons-2d7e4871b1bd5bab501cdbb3d0373b1617d0ebfa.zip
SCons-2d7e4871b1bd5bab501cdbb3d0373b1617d0ebfa.tar.gz
SCons-2d7e4871b1bd5bab501cdbb3d0373b1617d0ebfa.tar.bz2
Merge pull request #3143 from MatthewMarinets/JavaParserFix
Updated the JavaCommon parser to deal with constructor-implementation conflicts
-rw-r--r--src/CHANGES.txt4
-rw-r--r--src/engine/SCons/Tool/JavaCommon.py97
-rw-r--r--src/engine/SCons/Tool/JavaCommonTests.py43
3 files changed, 132 insertions, 12 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 703bebb..79d25db 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -7,6 +7,10 @@
RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
+ From Matthew Marinets
+ - Fixed an issue that caused the Java emitter to incorrectly parse arguments to constructors that
+ implemented a class.
+
From Bernard Blackham:
- Fixed handling of side-effects in task master (fixes #3013).
diff --git a/src/engine/SCons/Tool/JavaCommon.py b/src/engine/SCons/Tool/JavaCommon.py
index dfb9e33..7a065ca 100644
--- a/src/engine/SCons/Tool/JavaCommon.py
+++ b/src/engine/SCons/Tool/JavaCommon.py
@@ -37,6 +37,10 @@ java_parsing = 1
default_java_version = '1.4'
+# a switch for which jdk versions to use the Scope state for smarter
+# anonymous inner class parsing.
+scopeStateVersions = ('1.8')
+
if java_parsing:
# Parse Java files for class names.
#
@@ -64,7 +68,7 @@ if java_parsing:
interfaces, and anonymous inner classes."""
def __init__(self, version=default_java_version):
- if not version in ('1.1', '1.2', '1.3','1.4', '1.5', '1.6', '1.7',
+ if not version in ('1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7',
'1.8', '5', '6'):
msg = "Java version %s not supported" % version
raise NotImplementedError(msg)
@@ -115,8 +119,8 @@ if java_parsing:
ret = SkipState(1, self)
self.skipState = ret
return ret
-
- def __getAnonStack(self):
+
+ def _getAnonStack(self):
return self.anonStacksStack[-1]
def openBracket(self):
@@ -125,15 +129,16 @@ if java_parsing:
def closeBracket(self):
self.brackets = self.brackets - 1
if len(self.stackBrackets) and \
- self.brackets == self.stackBrackets[-1]:
+ self.brackets == self.stackBrackets[-1]:
self.listOutputs.append('$'.join(self.listClasses))
self.localClasses.pop()
self.listClasses.pop()
self.anonStacksStack.pop()
self.stackBrackets.pop()
if len(self.stackAnonClassBrackets) and \
- self.brackets == self.stackAnonClassBrackets[-1]:
- self.__getAnonStack().pop()
+ self.brackets == self.stackAnonClassBrackets[-1] and \
+ self.version not in scopeStateVersions:
+ self._getAnonStack().pop()
self.stackAnonClassBrackets.pop()
def parseToken(self, token):
@@ -175,17 +180,83 @@ if java_parsing:
self.stackAnonClassBrackets.append(self.brackets)
className = []
className.extend(self.listClasses)
- self.__getAnonStack()[-1] = self.__getAnonStack()[-1] + 1
- for anon in self.__getAnonStack():
+ self._getAnonStack()[-1] = self._getAnonStack()[-1] + 1
+ for anon in self._getAnonStack():
className.append(str(anon))
self.listOutputs.append('$'.join(className))
self.nextAnon = self.nextAnon + 1
- self.__getAnonStack().append(0)
+ self._getAnonStack().append(0)
def setPackage(self, package):
self.package = package
+ class ScopeState(object):
+ """
+ A state that parses code within a scope normally,
+ within the confines of a scope.
+ """
+ def __init__(self, old_state):
+ self.outer_state = old_state.outer_state
+ self.old_state = old_state
+ self.brackets = 0
+
+ def __getClassState(self):
+ try:
+ return self.classState
+ except AttributeError:
+ ret = ClassState(self)
+ self.classState = ret
+ return ret
+
+ def __getAnonClassState(self):
+ try:
+ return self.anonState
+ except AttributeError:
+ ret = SkipState(1, AnonClassState(self))
+ self.anonState = ret
+ return ret
+
+ def __getSkipState(self):
+ try:
+ return self.skipState
+ except AttributeError:
+ ret = SkipState(1, self)
+ self.skipState = ret
+ return ret
+
+ def openBracket(self):
+ self.brackets = self.brackets + 1
+
+ def closeBracket(self):
+ self.brackets = self.brackets - 1
+
+ def parseToken(self, token):
+ # if self.brackets == 0:
+ # return self.old_state.parseToken(token)
+ if token[:2] == '//':
+ return IgnoreState('\n', self)
+ elif token == '/*':
+ return IgnoreState('*/', self)
+ elif token == '{':
+ self.openBracket()
+ elif token == '}':
+ self.closeBracket()
+ if self.brackets == 0:
+ self.outer_state._getAnonStack().pop()
+ return self.old_state
+ elif token in ['"', "'"]:
+ return IgnoreState(token, self)
+ elif token == "new":
+ # anonymous inner class
+ return self.__getAnonClassState()
+ elif token == '.':
+ # Skip the attribute, it might be named "class", in which
+ # case we don't want to treat the following token as
+ # an inner class name...
+ return self.__getSkipState()
+ return self
+
class AnonClassState(object):
"""A state that looks for anonymous inner classes."""
def __init__(self, old_state):
@@ -212,13 +283,15 @@ if java_parsing:
if token == 'new':
# look further for anonymous inner class
return SkipState(1, AnonClassState(self))
- elif token in [ '"', "'" ]:
+ elif token in ['"', "'"]:
return IgnoreState(token, self)
elif token == ')':
self.brace_level = self.brace_level - 1
return self
if token == '{':
self.outer_state.addAnonClass()
+ if self.outer_state.version in scopeStateVersions:
+ return ScopeState(old_state = self.old_state).parseToken(token)
return self.old_state.parseToken(token)
class SkipState(object):
@@ -247,8 +320,8 @@ if java_parsing:
# 'Foo$1Inner'
# https://github.com/SCons/scons/issues/2087
if self.outer_state.localClasses and \
- self.outer_state.stackBrackets[-1] > \
- self.outer_state.stackBrackets[-2]+1:
+ self.outer_state.stackBrackets[-1] > \
+ self.outer_state.stackBrackets[-2]+1:
locals = self.outer_state.localClasses[-1]
try:
idx = locals[token]
diff --git a/src/engine/SCons/Tool/JavaCommonTests.py b/src/engine/SCons/Tool/JavaCommonTests.py
index cda785f..10be671 100644
--- a/src/engine/SCons/Tool/JavaCommonTests.py
+++ b/src/engine/SCons/Tool/JavaCommonTests.py
@@ -564,6 +564,49 @@ public class Foo
assert expect == classes, (expect, classes)
+ def test_in_function_class_declaration(self):
+ """
+ Test that implementing a class in a function call doesn't confuse SCons.
+ """
+
+ input = """
+package com.Matthew;
+
+public class AnonDemo {
+
+ public static void main(String[] args) {
+ new AnonDemo().execute();
+ }
+
+ public void execute() {
+ Foo bar = new Foo(new Foo() {
+ @Override
+ public int getX() { return this.x; }
+ }) {
+ @Override
+ public int getX() { return this.x; }
+ };
+ }
+
+ public abstract class Foo {
+ public int x;
+ public abstract int getX();
+
+ public Foo(Foo f) {
+ this.x = f.x;
+ }
+
+ public Foo() {}
+ }
+}
+"""
+ expect = ['AnonDemo$1',
+ 'AnonDemo$2',
+ 'AnonDemo$Foo',
+ 'AnonDemo']
+ pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.8')
+ assert expect == classes, (expect, classes)
+
if __name__ == "__main__":
unittest.main()