Fix for  Bug 516731: [9] DOM AST for (restricted) keywords in
ModuleDeclaration - open modifier changes
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter9Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter9Test.java
index b7af7ac..b5b62e4 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter9Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter9Test.java
@@ -160,17 +160,18 @@
 				+ "}";
 		this.workingCopies[0] = getWorkingCopy(
 				"/Converter9/src/module-info.java", content);
-		
+
 		CompilationUnit unit = (CompilationUnit) runConversion(AST_INTERNAL_JLS9, this.workingCopies[0], false/*no bindings*/);
 		ModuleDeclaration moduleDecl = unit.getModule();
-		
+
+		assertFalse(moduleDecl.isOpen());
 		checkSourceRange(moduleDecl, content, content);
 		List<ModuleStatement> stmts = moduleDecl.moduleStatements();
 		assertTrue(stmts.size() > 0);
-		
+
 		RequiresStatement req = (RequiresStatement) stmts.get(0);
 		checkSourceRange(req, "requires second;", content);
-		
+
 		ExportsStatement exp = (ExportsStatement) stmts.get(1);
 		checkSourceRange(exp, "exports pack11 to third, fourth;", content);
 		checkSourceRange(exp.getName(), "pack11", content);
@@ -214,7 +215,7 @@
 			assertEquals("Not a compilation unit", ASTNode.COMPILATION_UNIT, node.getNodeType());
 			CompilationUnit unit = (CompilationUnit) node;
 			ModuleDeclaration moduleDecl = unit.getModule();
-
+			assertFalse(moduleDecl.isOpen());
 			checkSourceRange(moduleDecl, content, content);
 			List<ModuleStatement> stmts = moduleDecl.moduleStatements();
 			assertTrue(stmts.size() > 0);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingModuleDeclarationTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingModuleDeclarationTest.java
index 240e0d2..3885227 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingModuleDeclarationTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingModuleDeclarationTest.java
@@ -250,9 +250,60 @@
 			buf.append("    requires static transient module3;\n");
 			buf.append("    requires transient addedme;\n");
 		buf.append("}");
-			assertEqualString(preview, buf.toString());		
+			assertEqualString(preview, buf.toString());
 		} finally {
 			if (javaProject != null) deleteProject(javaProject);
 		}
 	}
+	public void testBug516731_0001_since_9() throws Exception {
+		IJavaProject javaProject = null;
+		try {
+			javaProject = createProject("P_9", JavaCore.VERSION_9);
+			IPackageFragmentRoot currentSourceFolder = getPackageFragmentRoot("P_9", "src");
+			IPackageFragment pack1= currentSourceFolder.getPackageFragment(Util.EMPTY_STRING);
+			StringBuffer buf= new StringBuffer();
+			buf.append("module first {\n");
+			buf.append("    requires existing;\n");
+			buf.append("}");
+			ICompilationUnit cu= pack1.createCompilationUnit("module-info.java", buf.toString(), false, null);
+			CompilationUnit astRoot= createAST(cu);
+			ASTRewrite rewrite= ASTRewrite.create(astRoot.getAST());
+			ModuleDeclaration moduleDecl = astRoot.getModule();
+			rewrite.set(moduleDecl, ModuleDeclaration.OPEN_PROPERTY, Boolean.TRUE, null);
+			String preview= evaluateRewrite(cu, rewrite);
+			buf= new StringBuffer();
+			buf.append("open module first {\n");
+			buf.append("    requires existing;\n");
+			buf.append("}");
+			assertEqualString(preview, buf.toString());
+		} finally {
+			if (javaProject != null) deleteProject(javaProject);
+		}
+	}
+	public void testBug516731_0002_since_9() throws Exception {
+		IJavaProject javaProject = null;
+		try {
+			javaProject = createProject("P_9", JavaCore.VERSION_9);
+			IPackageFragmentRoot currentSourceFolder = getPackageFragmentRoot("P_9", "src");
+			IPackageFragment pack1= currentSourceFolder.getPackageFragment(Util.EMPTY_STRING);
+			StringBuffer buf= new StringBuffer();
+			buf.append("open module first {\n");
+			buf.append("    requires existing;\n");
+			buf.append("}");
+			ICompilationUnit cu= pack1.createCompilationUnit("module-info.java", buf.toString(), false, null);
+			CompilationUnit astRoot= createAST(cu);
+			ASTRewrite rewrite= ASTRewrite.create(astRoot.getAST());
+			ModuleDeclaration moduleDecl = astRoot.getModule();
+			rewrite.set(moduleDecl, ModuleDeclaration.OPEN_PROPERTY, Boolean.FALSE, null);
+			String preview= evaluateRewrite(cu, rewrite);
+			buf= new StringBuffer();
+			buf.append("module first {\n");
+			buf.append("    requires existing;\n");
+			buf.append("}");
+			assertEqualString(preview, buf.toString());
+		} finally {
+			if (javaProject != null) deleteProject(javaProject);
+		}
+	}
+
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java
index 7a2ff12..c474942 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java
@@ -157,7 +157,7 @@
 		output.append(CharOperation.charToString(this.moduleName));
 		return output;
 	}
-	private boolean isOpen() {
+	public boolean isOpen() {
 		return (this.modifiers & ClassFileConstants.ACC_OPEN) != 0;
 	}
 	public StringBuffer printBody(int indent, StringBuffer output) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
index ca150ed..c8b2568 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
@@ -3302,7 +3302,8 @@
 		ModuleDeclaration moduleDecl = this.ast.newModuleDeclaration();
 		// TODO
 		//convert(moduleDeclaration.javadoc, moduleDecl);
-		setModifiers(moduleDecl, moduleDeclaration);
+		setAnnotations(moduleDecl, moduleDeclaration); // only annotations
+		moduleDecl.setOpen(moduleDeclaration.isOpen());
 		Name moduleName = getName(moduleDeclaration, CharOperation.splitOn('.', moduleDeclaration.moduleName), moduleDeclaration.sourcePositions);
 		moduleDecl.setName(moduleName);
 		moduleDecl.setSourceRange(moduleDeclaration.declarationSourceStart, moduleDeclaration.declarationSourceEnd - moduleDeclaration.declarationSourceStart + 1);
@@ -5287,9 +5288,9 @@
 		}
 	}
 
-	protected void setModifiers(ModuleDeclaration moduleDecl, org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration moduleDeclaration) {
+	protected void setAnnotations(ModuleDeclaration moduleDecl, org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration moduleDeclaration) {
 		this.scanner.resetTo(moduleDeclaration.declarationSourceStart, moduleDeclaration.sourceStart);
-		this.setModifiers(moduleDecl.modifiers(), moduleDeclaration.annotations, moduleDeclaration.sourceStart);
+		this.setModifiers(moduleDecl.annotations(), moduleDeclaration.annotations, moduleDeclaration.sourceStart);
 	}
 	/**
 	 * @param variableDecl
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
index 6eaac1d..73f39bb 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
@@ -1591,7 +1591,8 @@
 		}
 		ModuleDeclaration o = (ModuleDeclaration) other;
 		return (safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())
-				&& safeSubtreeListMatch(node.modifiers(), o.modifiers())
+				&& safeSubtreeListMatch(node.annotations(), o.annotations())
+				&& node.isOpen() == o.isOpen()
 				&& safeSubtreeMatch(node.getName(), o.getName())
 				&& safeSubtreeListMatch(node.moduleStatements(), o.moduleStatements()));
 	}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ModuleDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ModuleDeclaration.java
index e4d2afc..80c3cf6 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ModuleDeclaration.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ModuleDeclaration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2016 IBM Corporation and others.
+ * Copyright (c) 2017 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
@@ -14,7 +14,6 @@
 package org.eclipse.jdt.core.dom;
 
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -22,7 +21,7 @@
  *
  * <pre>
  * ModuleDeclaration:
- *  [ Javadoc ] { ExtendedModifier } <b>module</b> Name <b>{</b>
+ *  [ Javadoc ] { Annotation } [ <b>open</b> ] <b>module</b> Name <b>{</b>
  *        [ ExportsStatement | OpensStatement | RequiresStatement | UsesStatement | ProvidesStatement ]
  *  <b>}</b>
  * </pre>
@@ -30,7 +29,7 @@
  * </p>
  *
  * @since 3.13 BETA_JAVA9
- * 
+ *
  * @noextend This class is not intended to be subclassed by clients.
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
@@ -44,10 +43,17 @@
 			new ChildPropertyDescriptor(ModuleDeclaration.class, "javadoc", Javadoc.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$
 
 	/**
-	 * The "modifiers" structural property of this node type (element type: {@link IExtendedModifier}).
+	 * The "annotations" structural property of this node type (element type: {@link Annotation}).
 	 */
-	public static final ChildListPropertyDescriptor MODIFIERS_PROPERTY =
-			new ChildListPropertyDescriptor(ModuleDeclaration.class, "modifiers", IExtendedModifier.class, CYCLE_RISK); //$NON-NLS-1$
+	public static final ChildListPropertyDescriptor ANNOTATIONS_PROPERTY =
+		new ChildListPropertyDescriptor(ModuleDeclaration.class, "annotations", Annotation.class, NO_CYCLE_RISK); //$NON-NLS-1$
+
+
+	/**
+	 * The "open" structural property of this node type (type: {@link Boolean}).
+	 */
+	public static final SimplePropertyDescriptor OPEN_PROPERTY =
+		new SimplePropertyDescriptor(ModuleDeclaration.class, "open", boolean.class, MANDATORY); //$NON-NLS-1$
 
 	/**
 	 * The "name" structural property of this node type (child type: {@link Name}).
@@ -69,10 +75,11 @@
 	private static final List PROPERTY_DESCRIPTORS_9_0;
 
 	static {
-		List properyList = new ArrayList(5);
+		List properyList = new ArrayList(6);
 		createPropertyList(ModuleDeclaration.class, properyList);
 		addProperty(JAVADOC_PROPERTY, properyList);
-		addProperty(MODIFIERS_PROPERTY, properyList);
+		addProperty(ANNOTATIONS_PROPERTY, properyList);
+		addProperty(OPEN_PROPERTY, properyList);
 		addProperty(NAME_PROPERTY, properyList);
 		addProperty(MODULE_STATEMENTS_PROPERTY, properyList);
 		PROPERTY_DESCRIPTORS_9_0 = reapPropertyList(properyList);
@@ -99,12 +106,16 @@
 	private Javadoc optionalDocComment = null;
 
 	/**
-	 * The extended modifiers (element type: {@link IExtendedModifier}).
+	 * The extended annotations (element type: {@link Annotation}).
 	 * defaults to an empty list
-	 * (see constructor).
 	 *
 	 */
-	private ASTNode.NodeList modifiers = null;
+	private ASTNode.NodeList annotations = new ASTNode.NodeList(ANNOTATIONS_PROPERTY);
+
+	/**
+	 * open versus normal; defaults to normal module.
+	 */
+	private boolean isOpen = false;
 
 	/**
 	 * The referenced module name; lazily initialized; defaults to a unspecified,
@@ -121,7 +132,6 @@
 	ModuleDeclaration(AST ast) {
 		super(ast);
 		unsupportedBelow9();
-		this.modifiers = new ASTNode.NodeList(MODIFIERS_PROPERTY);
 	}
 
 	@Override
@@ -132,6 +142,21 @@
 	/* (omit javadoc for this method)
 	 * Method declared on ASTNode.
 	 */
+	final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) {
+		if (property == OPEN_PROPERTY) {
+			if (get) {
+				return isOpen();
+			} else {
+				setOpen(value);
+				return false;
+			}
+		}
+		// allow default implementation to flag the error
+		return super.internalGetSetBooleanProperty(property, get, value);
+	}
+	/* (omit javadoc for this method)
+	 * Method declared on ASTNode.
+	 */
 	final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
 		if (property == JAVADOC_PROPERTY) {
 			if (get) {
@@ -157,8 +182,8 @@
 	 * Method declared on ASTNode.
 	 */
 	final List internalGetChildListProperty(ChildListPropertyDescriptor property) {
-		if (property == MODIFIERS_PROPERTY) {
-			return modifiers();
+		if (property == ANNOTATIONS_PROPERTY) {
+			return annotations();
 		}
 		if (property == MODULE_STATEMENTS_PROPERTY) {
 			return moduleStatements();
@@ -178,7 +203,8 @@
 		ModuleDeclaration result = new ModuleDeclaration(target);
 		result.setSourceRange(getStartPosition(), getLength());
 		result.setJavadoc((Javadoc) ASTNode.copySubtree(target, getJavadoc()));
-		result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers()));
+		result.setOpen(isOpen());
+		result.annotations().addAll(ASTNode.copySubtrees(target, annotations()));
 		result.setName((SimpleName) getName().clone(target));
 		result.moduleStatements().addAll(ASTNode.copySubtrees(target, moduleStatements()));
 		return result;
@@ -196,7 +222,7 @@
 		if (visitChildren) {
 			// visit children in normal left to right reading order
 			acceptChild(visitor, getJavadoc());
-			acceptChildren(visitor, this.modifiers);
+			acceptChildren(visitor, this.annotations);
 			acceptChild(visitor, getName());
 			acceptChildren(visitor, this.moduleStatements);
 		}
@@ -227,27 +253,25 @@
 	}
 
 	/**
-	 * Returns the modifiers explicitly specified on this declaration.
-	 * <p>
-	 *  this method is a convenience method that
-	 * computes these flags from {@link #modifiers()}.
-	 * </p>
+	 * Returns whether this module declaration is open or not
 	 *
-	 * @return the bit-wise "or" of <code>Modifier</code> constants
-	 * @see Modifier
+	 * @return <code>true</code> if this is open, else
+	 *    <code>false</code>
 	 */
-	public int getModifiers() {
-		// convenience method -
-		// performance could be improved by caching computed flags
-		// but this would require tracking changes to this.modifiers
-		int computedmodifierFlags = Modifier.NONE;
-		for (Iterator it = modifiers().iterator(); it.hasNext(); ) {
-			Object x = it.next();
-			if (x instanceof Modifier) {
-				computedmodifierFlags |= ((Modifier) x).getKeyword().toFlagValue();
-			}
-		}
-		return computedmodifierFlags;
+	public boolean isOpen() {
+		return this.isOpen;
+	}
+
+	/**
+	 * Sets whether this module declaration is open or not
+	 *
+	 * @param isOpen <code>true</code> if this is open module,
+	 *    and <code>false</code> if not
+	 */
+	public void setOpen(boolean isOpen) {
+		preValueChange(OPEN_PROPERTY);
+		this.isOpen = isOpen;
+		postValueChange(OPEN_PROPERTY);
 	}
 
 	/**
@@ -291,14 +315,14 @@
 	}
 
 	/**
-	 * Returns the live ordered list of modifiers and annotations
+	 * Returns the live ordered list of annotations
 	 * of this declaration.
 	 *
-	 * @return the live list of modifiers and annotations
-	 *    (element type: {@link IExtendedModifier})
+	 * @return the live list of annotations
+	 *    (element type: {@link Annotation})
 	 */
-	public List modifiers() {
-		return this.modifiers;
+	public List annotations() {
+		return this.annotations;
 	}
 
 	/**
@@ -317,14 +341,14 @@
 
 	@Override
 	int memSize() {
-		return BASE_NODE_SIZE + 4 * 4;
+		return BASE_NODE_SIZE + 5 * 4;
 	}
 
 	@Override
 	int treeSize() {
 		return	memSize()
 			+ (this.optionalDocComment == null ? 0 : getJavadoc().treeSize())
-			+ this.modifiers.listSize()
+			+ this.annotations.listSize()
 			+ (this.name == null ? 0 : getName().treeSize())
 			+ this.moduleStatements.listSize();
 	}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
index 1422c1b..f6fba1f 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
@@ -1234,7 +1234,9 @@
 		if (node.getJavadoc() != null) {
 			node.getJavadoc().accept(this);
 		}
-		printModifiers(node.modifiers());
+		printModifiers(node.annotations());
+		if (node.isOpen())
+			this.buffer.append("open "); //$NON-NLS-1$
 		this.buffer.append("module"); //$NON-NLS-1$
 		this.buffer.append(" "); //$NON-NLS-1$
 		node.getName().accept(this);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
index f96ca35..76df944 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
@@ -2088,13 +2088,34 @@
 			return doVisitUnchangedChildren(node);
 		}
 		int pos= rewriteJavadoc(node, ModuleDeclaration.JAVADOC_PROPERTY);
-		pos= rewriteModifiers2(node, ModuleDeclaration.MODIFIERS_PROPERTY, pos);
+		pos= rewriteModifiers2(node, ModuleDeclaration.ANNOTATIONS_PROPERTY, pos);
+
+		RewriteEvent event= getEvent(node, ModuleDeclaration.OPEN_PROPERTY);
+		if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) {
+			boolean fakeInModule = getScanner().getScanner().fakeInModule;
+			try {
+				boolean wasOpen= ((Boolean) event.getOriginalValue()).booleanValue();
+				if (wasOpen) {
+					this.tokenScanner.getScanner().fakeInModule = true;
+					int endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNamemodule, pos);
+					doTextRemove(pos, endPos - pos, getEditGroup(event));
+				} else {
+					doTextInsert(pos, "open ", getEditGroup(event)); //$NON-NLS-1$
+				}
+			} catch (CoreException e) {
+				handleException(e);
+			} finally {
+				this.tokenScanner.getScanner().fakeInModule = fakeInModule;
+			}
+		}
+
 		pos= rewriteRequiredNode(node, ModuleDeclaration.NAME_PROPERTY);
 		int startPos = getPosAfterLeftBrace(pos);
 		int startIndent= getIndent(node.getStartPosition()) + 1;
+		boolean fakeInModule = this.tokenScanner.getScanner().fakeInModule;
 		this.tokenScanner.getScanner().fakeInModule = true;
 		rewriteParagraphList(node, ModuleDeclaration.MODULE_STATEMENTS_PROPERTY, startPos, startIndent, 0, 1);
-		this.tokenScanner.getScanner().fakeInModule = false;
+		this.tokenScanner.getScanner().fakeInModule = fakeInModule;
 		return false;
 	}
 
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
index 6850a42..35d8f27 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
@@ -804,7 +804,10 @@
 		if (javadoc != null) {
 			javadoc.accept(this);
 		}
-		visitList(node, ModuleDeclaration.MODIFIERS_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' '));
+		visitList(node, ModuleDeclaration.ANNOTATIONS_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' '));
+		if (getBooleanAttribute(node, ModuleDeclaration.OPEN_PROPERTY)) {
+			this.result.append("open ");//$NON-NLS-1$
+		}
 		this.result.append("module "); //$NON-NLS-1$
 		getChildNode(node, ModuleDeclaration.NAME_PROPERTY).accept(this);
 		this.result.append('{');