Update semantics of resource_definition

Change-Id: I1280231b9cb69f075736fb87f932c5928d892e16
Reviewed-on: https://fuchsia-review.googlesource.com/c/intellij-language-fidl/+/453897
Reviewed-by: Pascal Perez <pascallouis@google.com>
diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml
index 11965db..a399fa1 100644
--- a/resources/META-INF/plugin.xml
+++ b/resources/META-INF/plugin.xml
@@ -20,7 +20,7 @@
       <ul>
         <li><b>0.15</b>
           <ul>
-            <li>Add resource keyword </li>
+            <li>Add resource_definition keyword.</li>
           </ul>
         </li>
         <li><b>0.14</b>
@@ -115,7 +115,8 @@
   <depends>com.intellij.modules.lang</depends>
 
   <extensions defaultExtensionNs="com.intellij">
-    <fileTypeFactory implementation="fuchsia.developer.plugin.fidl.FidlFileTypeFactory"/>
+    <fileTypeFactory implementation="fuchsia.developer.plugin.fidl.DeprecatedFidlFileTypeFactory"/>
+    <fileType implementation="fuchsia.developer.plugin.fidl.FidlFileTypeFactory"/>
     <lang.parserDefinition language="Fidl"
         implementationClass="fuchsia.developer.plugin.fidl.FidlParserDefinition"/>
     <lang.syntaxHighlighterFactory language="Fidl"
diff --git a/src/fuchsia/developer/plugin/fidl/ContextAwareHighlighter.java b/src/fuchsia/developer/plugin/fidl/ContextAwareHighlighter.java
index c9af9f2..3e15a67 100644
--- a/src/fuchsia/developer/plugin/fidl/ContextAwareHighlighter.java
+++ b/src/fuchsia/developer/plugin/fidl/ContextAwareHighlighter.java
@@ -90,6 +90,7 @@
   }
 
   private static class NumberAndRadix {
+
     String representation;
     int radix;
   }
@@ -335,6 +336,75 @@
       }
     }
 
+    // The grammar allows `( declaration-modifiers )*` on all declarations, but the
+    // compiler limits this as follows:
+    // * A modifier cannot occur twice on the same declaration.
+    //    * The `flexible` and `strict` modifiers cannot be used together.
+    //    * The `flexible` and `strict` modifiers can only be used on `bits`, `enum`, and `union`.
+    // * The `resource` modifier can only be used on `struct`, `table`, and `union`.
+    if (element.getNode().findChildByType(Types.DECLARATION_MODIFIERS) != null) {
+      ASTNode flexible = null;
+      ASTNode strict = null;
+      ASTNode resource = null;
+      for (PsiElement sibling : element.getChildren()) {
+        ASTNode siblingNode = sibling.getNode();
+        if (siblingNode.getElementType() == Types.DECLARATION_MODIFIERS) {
+          ASTNode found;
+          found = siblingNode.findChildByType(Types.FLEXIBLE);
+          if (found != null) {
+            if (flexible == null) {
+              flexible = found;
+            } else {
+              holder.createErrorAnnotation(
+                  found, "The flexible modifier cannot be used twice in the same declaration");
+            }
+          }
+          found = siblingNode.findChildByType(Types.STRICT);
+          if (found != null) {
+            if (strict == null) {
+              strict = found;
+            } else {
+              holder.createErrorAnnotation(
+                  found, "The strict modifier cannot be used twice in the same declaration");
+            }
+          }
+          found = siblingNode.findChildByType(Types.RESOURCE);
+          if (found != null) {
+            if (resource == null) {
+              resource = found;
+            } else {
+              holder.createErrorAnnotation(
+                  found, "The found modifier cannot be used twice in the same declaration");
+            }
+          }
+        }
+      }
+      ASTNode currNode = element.getNode();
+      if (flexible != null || strict != null) {
+        if (thisType != Types.BITS_DECLARATION
+            && thisType != Types.ENUM_DECLARATION
+            && thisType != Types.UNION_DECLARATION) {
+          ASTNode theNode = flexible != null ? flexible : strict;
+          holder.createErrorAnnotation(
+              theNode,
+              "The `flexible` and `strict` modifiers can only be used on bits, enum, and union.");
+        }
+        if (flexible != null && strict != null) {
+          holder.createErrorAnnotation(
+              flexible, "The flexible and strict modifiers cannot be used together");
+        }
+      }
+      if (resource != null) {
+        if (thisType != Types.STRUCT_DECLARATION
+            && thisType != Types.TABLE_DECLARATION
+            && thisType != Types.UNION_DECLARATION) {
+          holder.createErrorAnnotation(
+              resource,
+              "The `flexible` and `strict` modifiers can only be used on bits, enum, and union.");
+        }
+      }
+    }
+
     // TODO: A service-member allows the more liberal type-constructor in the grammar, but the
     // compiler limits this to protocols.  This requires us to track legal protocol names.
   }
diff --git a/src/fuchsia/developer/plugin/fidl/DeprecatedFidlFileTypeFactory.java b/src/fuchsia/developer/plugin/fidl/DeprecatedFidlFileTypeFactory.java
new file mode 100644
index 0000000..206ff12
--- /dev/null
+++ b/src/fuchsia/developer/plugin/fidl/DeprecatedFidlFileTypeFactory.java
@@ -0,0 +1,15 @@
+// Copyright 2020 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package fuchsia.developer.plugin.fidl;
+
+import com.intellij.openapi.fileTypes.FileTypeConsumer;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+public class DeprecatedFidlFileTypeFactory extends FileTypeFactory {
+  public void createFileTypes(@NotNull FileTypeConsumer fileTypeConsumer) {
+    fileTypeConsumer.consume(FileType.INSTANCE);
+  }
+}
diff --git a/src/fuchsia/developer/plugin/fidl/Fidl.bnf b/src/fuchsia/developer/plugin/fidl/Fidl.bnf
index 5e847e3..7b1c0e5 100644
--- a/src/fuchsia/developer/plugin/fidl/Fidl.bnf
+++ b/src/fuchsia/developer/plugin/fidl/Fidl.bnf
@@ -50,7 +50,7 @@
                 union-declaration |
                 service-declaration
 
-declaration-modifiers ::= FLEXIBLE | STRICT
+declaration-modifiers ::= FLEXIBLE | STRICT | RESOURCE
 
 const-declaration ::= attribute-list? CONST type-constructor identifier-token EQUALS constant
 
@@ -97,7 +97,7 @@
 
 type-alias-declaration ::= attribute-list? USING_T identifier-token EQUALS type-constructor
 
-resource-declaration ::= attribute-list? RESOURCE identifier-token COLON UINT32 OBRACE resource-properties CBRACE
+resource-declaration ::= attribute-list? RESOURCE_DEFINITION identifier-token COLON UINT32 OBRACE resource-properties CBRACE
 
 resource-properties ::= PROPERTIES OBRACE (type-constructor identifier-token SEMICOLON)* CBRACE SEMICOLON
 
@@ -144,4 +144,4 @@
                      FLOAT64 | INT8 | INT16 | INT32 | INT64 | UINT8 | UINT16 | UINT32 | UINT64 |
                      TRUE | FALSE | PROTOCOL | COMPOSE | BITS | BYTES | EXCEPTION | STRICT |
                      IOMMU | PAGER | PCIDEVICE | PMT | SUSPENDTOKEN | VCPU | SERVICE | FLEXIBLE |
-                     CLOCK
+                     CLOCK | RESOURCE_DEFINITION
diff --git a/src/fuchsia/developer/plugin/fidl/FidlFileTypeFactory.java b/src/fuchsia/developer/plugin/fidl/FidlFileTypeFactory.java
index 9c80efc..69bef3d 100644
--- a/src/fuchsia/developer/plugin/fidl/FidlFileTypeFactory.java
+++ b/src/fuchsia/developer/plugin/fidl/FidlFileTypeFactory.java
@@ -5,11 +5,9 @@
 package fuchsia.developer.plugin.fidl;
 
 import com.intellij.openapi.fileTypes.FileTypeConsumer;
-import com.intellij.openapi.fileTypes.FileTypeFactory;
 import org.jetbrains.annotations.NotNull;
 
-public class FidlFileTypeFactory extends FileTypeFactory {
-  @Override
+public class FidlFileTypeFactory {
   public void createFileTypes(@NotNull FileTypeConsumer fileTypeConsumer) {
     fileTypeConsumer.consume(FileType.INSTANCE);
   }
diff --git a/src/fuchsia/developer/plugin/fidl/FidlLexer.flex b/src/fuchsia/developer/plugin/fidl/FidlLexer.flex
index 34a2ed1..637ec3b 100644
--- a/src/fuchsia/developer/plugin/fidl/FidlLexer.flex
+++ b/src/fuchsia/developer/plugin/fidl/FidlLexer.flex
@@ -47,6 +47,7 @@
 REQUEST=request
 RESERVED=reserved
 RESOURCE=resource
+RESOURCE_DEFINITION=resource_definition
 SERVICE=service
 STRING=string
 STRICT=strict
@@ -154,6 +155,7 @@
   {HANDLE} { return HANDLE; }
   {RESERVED} { return RESERVED; }
   {RESOURCE} { return RESOURCE; }
+  {RESOURCE_DEFINITION} { return RESOURCE_DEFINITION; }
   {PROPERTIES} { return PROPERTIES; }
   {STRICT} { return STRICT; }
   {FLEXIBLE} { return FLEXIBLE; }
diff --git a/src/fuchsia/developer/plugin/fidl/SyntaxHighlighter.java b/src/fuchsia/developer/plugin/fidl/SyntaxHighlighter.java
index f3b8e4c..2d0d78e 100644
--- a/src/fuchsia/developer/plugin/fidl/SyntaxHighlighter.java
+++ b/src/fuchsia/developer/plugin/fidl/SyntaxHighlighter.java
@@ -93,6 +93,7 @@
             Types.ERROR,
             Types.RESERVED,
             Types.RESOURCE,
+            Types.RESOURCE_DEFINITION,
             Types.PROPERTIES,
             Types.STRICT,
             Types.FLEXIBLE,