From: Jean Privat Date: Fri, 29 May 2015 01:40:09 +0000 (-0400) Subject: Merge: Nitg-g new NativeArray fix X-Git-Tag: v0.7.5~12 X-Git-Url: http://nitlanguage.org?hp=b50f90be46675872672b5634fa9b06f731882208 Merge: Nitg-g new NativeArray fix This is a bug that was discovered during the push of #1403. What happens is that since NativeArrays work only with boxed values, the copy_to operation could write data beyond its intended boundaries, hence corrupting random memory. If you execute the test bundled with the PR, on my machine, with `--hardening` on, you get this error: `BTD BUG: Dynamic type is Sys, static type is Array[Byte]` What happens here is that the `dest` of the `memmove` was in a emplacement before the `Array[Byte]` itself, due to its length and because the `memmove` used val* as sizeof value, it rewrote the classid of `self`, hence changing its dynamic type effectively from `Array[Byte]` to `Sys`, which produces the typing bug. If left too long to execute, or in an unlucky memory layout, it simply segfaulted. The behaviour of NEW_NativeArray henceforth is that it will reserve space for n `val*` instead of the `ctype` of the values. Pull-Request: #1417 Reviewed-by: Jean Privat Reviewed-by: Romain Chanoir --- diff --git a/contrib/objcwrapper/header_static/makefile b/contrib/objcwrapper/header_static/makefile new file mode 100644 index 0000000..e4d3e19 --- /dev/null +++ b/contrib/objcwrapper/header_static/makefile @@ -0,0 +1,7 @@ +bin/header_static: + mkdir -p bin + ../../../bin/nitc --dir bin src/header_static.nit + +tests: bin/header_static + cat CGGeometry.h | bin/header_static > static_CGGeometry.h + cat NSObject.h | bin/header_static > static_NSObject.h diff --git a/contrib/objcwrapper/header_static/src/header_static.nit b/contrib/objcwrapper/header_static/src/header_static.nit new file mode 100644 index 0000000..c43fe2a --- /dev/null +++ b/contrib/objcwrapper/header_static/src/header_static.nit @@ -0,0 +1,96 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Filters preprocessed C-like header files to remove static code and keep their signatures. +# +# This tool is used in the process of parsing header files to extract +# information on the declared services (the functions and structures). +# This information is then used to generate bindings for Nit code +# to access these services. +# +# The C header sometimes contains static code. It deletes static code of +# headers, but keep their signatures. This tool is an extension of +# header_keeper. It searches the keyword static to identify +# the static code, and ignores the code into their brackets. The result is +# printed to sdtout. +# +# ~~~sh +# cat Pre-Processed/CGGeometry.h | header_static > Pre-Processed/static_header.h +# ~~~ +# +# This module can also be used as a library. +# The main service is the method `header_static` +module header_static + +redef class Char + private fun is_endline: Bool do return "\};".has(self) +end + +# Filters the preprocessed `input` to keep signatures for static code and write to the `output` +fun header_static(input: Reader, output: Writer) do + var static_target = false + var static_attribute_target = false + var bracket_counter = 0 + var previous_letter = "" + var instruction = "" + var double_underscore = 0 + var position = 0 + + while not input.eof do + var line = input.read_line + if line.to_s.has("static") then static_target = true + + if static_target then + if line.to_s.has("__attribute__") then static_attribute_target = true + for letter in line do + if letter == '{' then bracket_counter += 1 + if letter == '}' then bracket_counter -= 1 + + if letter == '_' and previous_letter == "_" and bracket_counter == 0 then + double_underscore += 1 + end + + # Sometimes we lost space between return type and signature name, + # because he has a return line between both. + # We add a space before signature name for safety. + if bracket_counter == 0 and letter == '_' and double_underscore >= 1 and not static_attribute_target then + instruction = instruction.insert_at(" ", position - 2) + end + if bracket_counter == 0 and not letter.is_endline then instruction += letter.to_s + if bracket_counter == 0 and letter.is_endline then + instruction += ";" + static_target = false + static_attribute_target = false + end + + if bracket_counter == 0 and (letter == '}' and double_underscore >= 1 or letter == ';') then + output.write instruction + "\n" + end + + if letter.is_endline and bracket_counter == 0 then + double_underscore = 0 + position = 0 + instruction = "" + end + + previous_letter = letter.to_s + position += 1 + end + else + output.write line + "\n" + end + end +end + +header_static(sys.stdin, sys.stdout) diff --git a/lib/curl/curl.nit b/lib/curl/curl.nit index c087642..dbfc157 100644 --- a/lib/curl/curl.nit +++ b/lib/curl/curl.nit @@ -377,8 +377,7 @@ class CurlResponseSuccess var status_code = 0 # Receive body from request due to body callback registering - redef fun body_callback(line: String) - do + redef fun body_callback(line) do self.body_str = "{self.body_str}{line}" end end diff --git a/lib/curl/examples/curl_http.nit b/lib/curl/examples/curl_http.nit index 079f12c..948ba38 100644 --- a/lib/curl/examples/curl_http.nit +++ b/lib/curl/examples/curl_http.nit @@ -32,16 +32,16 @@ class MyHttpFetcher fun destroy do self.curl.destroy # Header callback - redef fun header_callback(line: String) do + redef fun header_callback(line) do # We keep this callback silent for testing purposes #if not line.has_prefix("Date:") then print "Header_callback : {line}" end # Body callback - redef fun body_callback(line: String) do self.our_body = "{self.our_body}{line}" + redef fun body_callback(line) do self.our_body = "{self.our_body}{line}" # Stream callback - Cf : No one is registered - redef fun stream_callback(buffer: String, size: Int, count: Int) do print "Stream_callback : {buffer} - {size} - {count}" + redef fun stream_callback(buffer, size, count) do print "Stream_callback : {buffer} - {size} - {count}" end diff --git a/lib/geometry/boxes.nit b/lib/geometry/boxes.nit index b8c9798..5ec269d 100644 --- a/lib/geometry/boxes.nit +++ b/lib/geometry/boxes.nit @@ -211,7 +211,7 @@ interface Boxed3d[N: Numeric] (self.back <= other.front and other.back <= self.front)) end - redef fun padded(dist: N): Box3d[N] do return new Box3d[N].lrtbfb(left - dist, right + dist, top + dist, bottom - dist, front + dist, back - dist) + redef fun padded(dist): Box3d[N] do return new Box3d[N].lrtbfb(left - dist, right + dist, top + dist, bottom - dist, front + dist, back - dist) end # A 3d bounded object and an implementation of Boxed @@ -344,8 +344,8 @@ class BoxedArray[E: Boxed[Numeric]] private var data: Array[E] = new Array[E] - redef fun add(item: E) do data.add(item) - redef fun items_overlapping(item: Boxed[Numeric]): SimpleCollection[E] + redef fun add(item) do data.add(item) + redef fun items_overlapping(item): SimpleCollection[E] do var arr = new Array[E] for i in data do diff --git a/lib/geometry/points_and_lines.nit b/lib/geometry/points_and_lines.nit index 303aae1..6c7fda6 100644 --- a/lib/geometry/points_and_lines.nit +++ b/lib/geometry/points_and_lines.nit @@ -71,8 +71,8 @@ end class Line[N: Numeric] super ILine[N] - redef var point_left: P - redef var point_right: P + redef var point_left + redef var point_right init do diff --git a/lib/geometry/quadtree.nit b/lib/geometry/quadtree.nit index 089b6ee..0218406 100644 --- a/lib/geometry/quadtree.nit +++ b/lib/geometry/quadtree.nit @@ -55,14 +55,14 @@ abstract class QuadTree[E: Boxed[Numeric]] self.parent_node = parent end - redef fun items_overlapping(region :Boxed[Numeric]): SimpleCollection[E] do + redef fun items_overlapping(region): SimpleCollection[E] do var res = new Array[E] items_overlapping_in(region,res) return res end # add the item to the tree, create children if the limit is reached - redef fun add(item: E) do if self.is_leaf then self.data.add(item) else add_to_children(item) + redef fun add(item) do if self.is_leaf then self.data.add(item) else add_to_children(item) private fun add_to_children(item: Boxed[Numeric]) do @@ -93,7 +93,7 @@ abstract class QuadTree[E: Boxed[Numeric]] end end - redef fun is_empty: Bool do return data.is_empty and (self.is_leaf or (child0.is_empty and child1.is_empty and child2.is_empty and child3.is_empty)) + redef fun is_empty do return data.is_empty and (self.is_leaf or (child0.is_empty and child1.is_empty and child2.is_empty and child3.is_empty)) # Return whether or not the Node is a leaf of the tree fun is_leaf: Bool do return child0 == null diff --git a/lib/json/dynamic.nit b/lib/json/dynamic.nit index d0559e0..594aac6 100644 --- a/lib/json/dynamic.nit +++ b/lib/json/dynamic.nit @@ -131,8 +131,7 @@ class JsonValue # assert "123".to_json_value.to_s == "123" # assert "true".to_json_value.to_s == "true" # assert "[1, 2, 3]".to_json_value.to_s == "123" - redef fun to_s: String - do + redef fun to_s do if value == null then return "null" return value.to_s end diff --git a/lib/neo4j/graph/graph.nit b/lib/neo4j/graph/graph.nit index 2ffa800..12a2b9f 100644 --- a/lib/neo4j/graph/graph.nit +++ b/lib/neo4j/graph/graph.nit @@ -105,7 +105,7 @@ abstract class NeoNodeCollection # # SEE: `create_node` # SEE: `register` - redef fun add(node: NeoNode) is abstract + redef fun add(node) is abstract # Add a new node to the graph and return it. # diff --git a/lib/neo4j/graph/json_graph_store.nit b/lib/neo4j/graph/json_graph_store.nit index fb5ffd0..898c059 100644 --- a/lib/neo4j/graph/json_graph_store.nit +++ b/lib/neo4j/graph/json_graph_store.nit @@ -297,7 +297,7 @@ redef class NeoNode redef fun to_s do return to_json # Append the JSON representation of the node to the specified buffer. - redef fun append_json_for(graph: NeoGraph, buffer: Buffer) do + redef fun append_json_for(graph, buffer) do append_json(buffer) end end @@ -307,7 +307,7 @@ redef class NeoEdge # Append the JSON representation of the relationship to the specified buffer. # # Use the IDs specfied by `graph.nodes`. - redef fun append_json_for(graph: NeoGraph, buffer: Buffer) do + redef fun append_json_for(graph, buffer) do buffer.append "\{\"type\":" rel_type.append_json(buffer) buffer.append ",\"properties\":" diff --git a/lib/neo4j/graph/sequential_id.nit b/lib/neo4j/graph/sequential_id.nit index fb6129f..939ed88 100644 --- a/lib/neo4j/graph/sequential_id.nit +++ b/lib/neo4j/graph/sequential_id.nit @@ -63,7 +63,7 @@ class SequentialNodeCollection return nodes[id] end - redef fun has_id(id: Int): Bool do + redef fun has_id(id) do return id >= 0 and id < nodes.length and nodes[id] isa NeoNode end diff --git a/lib/nitcorn/http_response.nit b/lib/nitcorn/http_response.nit index 666974b..ef87adb 100644 --- a/lib/nitcorn/http_response.nit +++ b/lib/nitcorn/http_response.nit @@ -50,7 +50,7 @@ class HttpResponse end # Get this reponse as a string according to HTTP protocol - redef fun to_s: String + redef fun to_s do finalize diff --git a/lib/sax/helpers/attributes_impl.nit b/lib/sax/helpers/attributes_impl.nit index f54ec0f..64691cd 100644 --- a/lib/sax/helpers/attributes_impl.nit +++ b/lib/sax/helpers/attributes_impl.nit @@ -31,9 +31,9 @@ class AttributesImpl super Attributes private var data = new Array[String] - redef var length: Int = 0 + redef var length = 0 - redef fun uri(index: Int): nullable String do + redef fun uri(index) do if index >= 0 and index < length then return data[index * 5] else @@ -41,7 +41,7 @@ class AttributesImpl end end - redef fun local_name(index: Int): nullable String do + redef fun local_name(index) do if index >= 0 and index < length then return data[index * 5 + 1] else @@ -49,7 +49,7 @@ class AttributesImpl end end - redef fun qname(index: Int): nullable String do + redef fun qname(index) do if index >= 0 and index < length then return data[index * 5 + 2] else @@ -85,7 +85,7 @@ class AttributesImpl # are not available. # # SEE: `length` - redef fun type_of(index): nullable String do + redef fun type_of(index) do if index isa Int then if index >= 0 and index < length then return data[index * 5 + 3] @@ -124,7 +124,7 @@ class AttributesImpl # are not available. # # SEE: `length` - redef fun value_of(index): nullable String do + redef fun value_of(index) do if index isa Int then if index >= 0 and index < length then return data[index * 5 + 4] @@ -157,7 +157,7 @@ class AttributesImpl # # The index of the attribute, or -1 if it does not # appear in the list. - redef fun index_ns(uri: String, local_name: String): Int do + redef fun index_ns(uri, local_name) do var i = 0 if "" != local_name then @@ -184,7 +184,7 @@ class AttributesImpl # # The index of the attribute, or -1 if it does not # appear in the list. - redef fun index_of(qname: String): Int do + redef fun index_of(qname) do var i = 0 if "" != qname then @@ -218,7 +218,7 @@ class AttributesImpl # The attribute type as a string, or `null` if the # attribute is not in the list or if Namespace # processing is not being performed. - redef fun type_ns(uri: String, local_name: String): nullable String do + redef fun type_ns(uri, local_name) do var i = 0 if "" != local_name then @@ -252,7 +252,7 @@ class AttributesImpl # The attribute value as a string, or `null` if the # attribute is not in the list or if Namespace # processing is not being performed. - redef fun value_ns(uri: String, local_name: String): nullable String do + redef fun value_ns(uri, local_name) do var i = 0 if "" != local_name then diff --git a/lib/sax/helpers/sax_locator_impl.nit b/lib/sax/helpers/sax_locator_impl.nit index 99d0228..185f074 100644 --- a/lib/sax/helpers/sax_locator_impl.nit +++ b/lib/sax/helpers/sax_locator_impl.nit @@ -19,19 +19,21 @@ import sax::sax_locator # can use it to make a persistent snapshot of a locator at any # point during a document parse: # -# import sax::helpers::sax_locator_impl -# import sax::content_handler +# ~~~nitish +# import sax::helpers::sax_locator_impl +# import sax::content_handler # -# class Example super ContentHandler -# private var locator: SAXLocator -# private var start_loc: nullable SAXLocator = null +# class Example super ContentHandler +# private var locator: SAXLocator +# private var start_loc: nullable SAXLocator = null # -# redef fun start_document do -# # save the location of the start of the document -# # for future use. -# start_loc = new SAXLocatorImpl.from(locator) -# end +# redef fun start_document do +# # save the location of the start of the document +# # for future use. +# start_loc = new SAXLocatorImpl.from(locator) # end +# end +# ~~~ # # Normally, parser writers will not use this class, since it # is more efficient to provide location information only when @@ -40,10 +42,10 @@ import sax::sax_locator # Note: The original source code and documentation of this class comes, in part, # from [SAX 2.0](http://www.saxproject.org). class SAXLocatorImpl super SAXLocator - redef var public_id: nullable String = null is writable - redef var system_id: nullable String = null is writable - redef var line_number: Int = -1 is writable - redef var column_number: Int = -1 is writable + redef var public_id = null is writable + redef var system_id = null is writable + redef var line_number = -1 is writable + redef var column_number = -1 is writable # Zero-argument constructor. # diff --git a/lib/sax/helpers/xml_filter_impl.nit b/lib/sax/helpers/xml_filter_impl.nit index 7bcd021..78efef9 100644 --- a/lib/sax/helpers/xml_filter_impl.nit +++ b/lib/sax/helpers/xml_filter_impl.nit @@ -42,14 +42,14 @@ class XMLFilterImpl # XMLFilter - redef var parent: nullable XMLReader = null is writable + redef var parent = null is writable # XMLReader - redef var entity_resolver: nullable EntityResolver = null is writable - redef var dtd_handler: nullable DTDHandler = null is writable - redef var content_handler: nullable ContentHandler = null is writable - redef var error_handler: nullable ErrorHandler = null is writable + redef var entity_resolver = null is writable + redef var dtd_handler = null is writable + redef var content_handler = null is writable + redef var error_handler = null is writable ############################################################################ @@ -73,7 +73,7 @@ class XMLFilterImpl parent = parent_reader end - redef fun feature_recognized(name: String): Bool do + redef fun feature_recognized(name) do if parent == null then return false else @@ -81,7 +81,7 @@ class XMLFilterImpl end end - redef fun feature_readable(name: String): Bool do + redef fun feature_readable(name) do if parent == null then return false else @@ -89,7 +89,7 @@ class XMLFilterImpl end end - redef fun feature_writable(name: String): Bool do + redef fun feature_writable(name) do if parent == null then return false else @@ -112,7 +112,7 @@ class XMLFilterImpl # SEE: `feature_recognized` # # SEE: `feature_readable` - redef fun feature(name: String): Bool do + redef fun feature(name) do assert sax_recognized: parent != null else sys.stderr.write("Feature: {name}\n") end @@ -136,14 +136,14 @@ class XMLFilterImpl # SEE: `feature_recognized` # # SEE: `feature_writable` - redef fun feature=(name: String, value: Bool) do + redef fun feature=(name, value) do assert sax_recognized: parent != null else sys.stderr.write("Feature: {name}\n") end parent.feature(name) = value end - redef fun property_recognized(name: String): Bool do + redef fun property_recognized(name) do if parent == null then return false else @@ -151,7 +151,7 @@ class XMLFilterImpl end end - redef fun property_readable(name: String): Bool do + redef fun property_readable(name) do if parent == null then return false else @@ -159,7 +159,7 @@ class XMLFilterImpl end end - redef fun property_writable(name: String): Bool do + redef fun property_writable(name) do if parent == null then return false else @@ -180,7 +180,7 @@ class XMLFilterImpl # SEE: `property_recognized` # # SEE: `property_readable` - redef fun property(name: String): nullable Object do + redef fun property(name) do assert sax_recognized: parent != null else sys.stderr.write("Property: {name}\n") end @@ -204,19 +204,19 @@ class XMLFilterImpl # SEE: `property_recognized` # # SEE: `property_writable` - redef fun property=(name: String, value: nullable Object) do + redef fun property=(name, value) do assert sax_recognized: parent != null else sys.stderr.write("Property: {name}\n") end parent.property(name) = value end - redef fun parse(input: InputSource) do + redef fun parse(input) do setup_parse parent.parse(input) end - redef fun parse_file(system_id: String) do + redef fun parse_file(system_id) do var source = new InputSource source.system_id = system_id @@ -227,9 +227,7 @@ class XMLFilterImpl ############################################################################ # EntityResolver - redef fun resolve_entity(public_id: nullable String, - system_id: nullable String): - nullable InputSource do + redef fun resolve_entity(public_id, system_id) do if entity_resolver == null then return null else @@ -241,15 +239,13 @@ class XMLFilterImpl ############################################################################ # DTDHandler - redef fun notation_decl(name: String, public_id: String, - system_id: String) do + redef fun notation_decl(name, public_id, system_id) do if dtd_handler != null then dtd_handler.notation_decl(name, public_id, system_id) end end - redef fun unparsed_entity_decl(name: String, public_id: String, - system_id: String) do + redef fun unparsed_entity_decl(name, public_id, system_id) do if dtd_handler != null then dtd_handler.unparsed_entity_decl(name, public_id, system_id) end @@ -259,7 +255,7 @@ class XMLFilterImpl ############################################################################ # ContentHandler - redef fun document_locator=(locator: SAXLocator) do + redef fun document_locator=(locator) do if content_handler != null then content_handler.document_locator = locator end @@ -277,50 +273,49 @@ class XMLFilterImpl end end - redef fun start_prefix_mapping(prefix: String, uri: String) do + redef fun start_prefix_mapping(prefix, uri) do if content_handler != null then content_handler.start_prefix_mapping(prefix, uri) end end - redef fun end_prefix_mapping(prefix: String) do + redef fun end_prefix_mapping(prefix) do if content_handler != null then content_handler.end_prefix_mapping(prefix) end end - redef fun start_element(uri: String, local_name: String, qname: String, - atts: Attributes) do + redef fun start_element(uri, local_name, qname, atts) do if content_handler != null then content_handler.start_element(uri, local_name, qname, atts) end end - redef fun end_element(uri: String, local_name: String, qname: String) do + redef fun end_element(uri, local_name, qname) do if content_handler != null then content_handler.end_element(uri, local_name, qname) end end - redef fun characters(str: String) do + redef fun characters(str) do if content_handler != null then content_handler.characters(str) end end - redef fun ignorable_whitespace(str: String) do + redef fun ignorable_whitespace(str) do if content_handler != null then content_handler.ignorable_whitespace(str) end end - redef fun processing_instruction(target: String, data: nullable String) do + redef fun processing_instruction(target, data) do if content_handler != null then content_handler.processing_instruction(target, data) end end - redef fun skipped_entity(name: String) do + redef fun skipped_entity(name) do if content_handler != null then content_handler.skipped_entity(name) end @@ -330,19 +325,19 @@ class XMLFilterImpl ############################################################################ # ErrorHandler - redef fun warning(exception: SAXParseException) do + redef fun warning(exception) do if error_handler != null then error_handler.warning(exception) end end - redef fun error(exception: SAXParseException) do + redef fun error(exception) do if error_handler != null then error_handler.error(exception) end end - redef fun fatal_error(exception: SAXParseException) do + redef fun fatal_error(exception) do if error_handler != null then error_handler.fatal_error(exception) else diff --git a/lib/saxophonit/saxophonit.nit b/lib/saxophonit/saxophonit.nit index 6b3f616..19dbb69 100644 --- a/lib/saxophonit/saxophonit.nit +++ b/lib/saxophonit/saxophonit.nit @@ -68,63 +68,63 @@ class XophonReader private var model = new XophonReaderModel private var lexer: XophonLexer is noinit - redef fun entity_resolver: nullable EntityResolver do return model.entity_resolver - redef fun entity_resolver=(entity_resolver: nullable EntityResolver) do + redef fun entity_resolver do return model.entity_resolver + redef fun entity_resolver=(entity_resolver) do model.entity_resolver = entity_resolver end - redef fun dtd_handler: nullable DTDHandler do return model.dtd_handler - redef fun dtd_handler=(dtd_handler: nullable DTDHandler) do + redef fun dtd_handler do return model.dtd_handler + redef fun dtd_handler=(dtd_handler) do model.dtd_handler = dtd_handler end - redef fun content_handler: nullable ContentHandler do return model.content_handler - redef fun content_handler=(content_handler: nullable ContentHandler) do + redef fun content_handler do return model.content_handler + redef fun content_handler=(content_handler) do model.content_handler = content_handler end - redef fun error_handler: nullable ErrorHandler do return model.error_handler - redef fun error_handler=(error_handler: nullable ErrorHandler) do + redef fun error_handler do return model.error_handler + redef fun error_handler=(error_handler) do model.error_handler = error_handler end - redef fun feature_recognized(name: String): Bool do + redef fun feature_recognized(name) do return model.feature_recognized(name) end - redef fun feature_readable(name: String): Bool do + redef fun feature_readable(name) do return model.feature_readable(name) end - redef fun feature_writable(name: String): Bool do + redef fun feature_writable(name) do return model.feature_readable(name) end - redef fun feature(name: String): Bool do return model.feature(name) - redef fun feature=(name: String, value: Bool) do model.feature(name) = value + redef fun feature(name) do return model.feature(name) + redef fun feature=(name, value) do model.feature(name) = value - redef fun property_recognized(name: String): Bool do + redef fun property_recognized(name) do return model.property_recognized(name) end - redef fun property_readable(name: String): Bool do + redef fun property_readable(name) do return model.property_readable(name) end - redef fun property_writable(name: String): Bool do + redef fun property_writable(name) do return model.property_writable(name) end - redef fun property(name: String): nullable Object do + redef fun property(name) do return model.property(name) end - redef fun property=(name: String, value: nullable Object) do + redef fun property=(name, value) do model.property(name) = value end - redef fun parse(input: InputSource) do + redef fun parse(input) do var system_id: nullable MaybeError[String, Error] = null model.locator = new SAXLocatorImpl @@ -157,7 +157,7 @@ class XophonReader end end - redef fun parse_file(system_id: String) do + redef fun parse_file(system_id) do parse(new InputSource.with_system_id(system_id)) end diff --git a/lib/saxophonit/testing.nit b/lib/saxophonit/testing.nit index 70db6a5..cc69c83 100644 --- a/lib/saxophonit/testing.nit +++ b/lib/saxophonit/testing.nit @@ -259,7 +259,7 @@ class SAXEventLogger ############################################################################ # XMLReader - redef fun property(name: String): nullable Object do + redef fun property(name) do assert sax_recognized: parent != null else sys.stderr.write("Property: {name}\n") end @@ -278,7 +278,7 @@ class SAXEventLogger end end - redef fun property=(name: String, value: nullable Object) do + redef fun property=(name, value) do assert sax_recognized: parent != null else sys.stderr.write("Property: {name}\n") end @@ -297,7 +297,7 @@ class SAXEventLogger end end - redef fun parse(input: InputSource) do + redef fun parse(input) do assert parent_is_not_null: parent != 0 else sys.stderr.write("No parent for filter.") end @@ -314,9 +314,7 @@ class SAXEventLogger ############################################################################ # EntityResolver - redef fun resolve_entity(public_id: nullable String, - system_id: nullable String): - nullable InputSource do + redef fun resolve_entity(public_id, system_id) do log.push(["resolve_entity", public_id or else "^NULL", system_id or else "^NULL"]) @@ -327,14 +325,12 @@ class SAXEventLogger ############################################################################ # DTDHandler - redef fun notation_decl(name: String, public_id: String, - system_id: String) do + redef fun notation_decl(name, public_id, system_id) do log.push(["notation_decl", name, public_id, system_id]) super end - redef fun unparsed_entity_decl(name: String, public_id: String, - system_id: String) do + redef fun unparsed_entity_decl(name, public_id, system_id) do log.push(["unparsed_entity_decl", name, public_id, system_id]) super end @@ -343,7 +339,7 @@ class SAXEventLogger ############################################################################ # ContentHandler - redef fun document_locator=(locator: SAXLocator) do + redef fun document_locator=(locator) do log.push(["document_locator=", locator.public_id or else "^NULL", locator.system_id or else "^NULL", @@ -362,18 +358,17 @@ class SAXEventLogger super end - redef fun start_prefix_mapping(prefix: String, uri: String) do + redef fun start_prefix_mapping(prefix, uri) do log.push(["start_prefix_mapping", prefix, uri]) super end - redef fun end_prefix_mapping(prefix: String) do + redef fun end_prefix_mapping(prefix) do log.push(["end_prefix_mapping", prefix]) super end - redef fun start_element(uri: String, local_name: String, qname: String, - atts: Attributes) do + redef fun start_element(uri, local_name, qname, atts) do var entry = new Array[String] var i = 0 var length = atts.length @@ -394,27 +389,27 @@ class SAXEventLogger super end - redef fun end_element(uri: String, local_name: String, qname: String) do + redef fun end_element(uri, local_name, qname) do log.push(["end_element", uri, local_name, qname]) super end - redef fun characters(str: String) do + redef fun characters(str) do log.push(["characters", str]) super end - redef fun ignorable_whitespace(str: String) do + redef fun ignorable_whitespace(str) do log.push(["ignorable_witespace", str]) super end - redef fun processing_instruction(target: String, data: nullable String) do + redef fun processing_instruction(target, data) do log.push(["processing_instruction", target, data or else "^NULL"]) super end - redef fun skipped_entity(name: String) do + redef fun skipped_entity(name) do log.push(["skipped_entity", name]) super end @@ -423,17 +418,17 @@ class SAXEventLogger ############################################################################ # ErrorHandler - redef fun warning(exception: SAXParseException) do + redef fun warning(exception) do log.push(["warning", exception.full_message]) super end - redef fun error(exception: SAXParseException) do + redef fun error(exception) do log.push(["error", exception.full_message]) super end - redef fun fatal_error(exception: SAXParseException) do + redef fun fatal_error(exception) do log.push(["fatal_error", exception.full_message]) if error_handler != null then error_handler.fatal_error(exception) @@ -444,18 +439,14 @@ class SAXEventLogger ############################################################################ # DeclHandler - redef fun element_decl(name: String, model: String) do + redef fun element_decl(name, model) do log.push(["element_decl", name, model]) if decl_handler != null then decl_handler.element_decl(name, model) end end - redef fun attribute_decl(element_name: String, - attribute_name: String, - attribute_type: String, - mode: nullable String, - value: nullable String) do + redef fun attribute_decl(element_name, attribute_name, attribute_type, mode, value) do log.push(["attribute_decl", element_name, attribute_name, @@ -468,14 +459,14 @@ class SAXEventLogger end end - redef fun internal_entity_decl(name: String, value: String) do + redef fun internal_entity_decl(name, value) do log.push(["internal_entity_decl", name, value]) if decl_handler != null then decl_handler.internal_entity_decl(name, value) end end - redef fun external_entity_decl(name: String, value: String) do + redef fun external_entity_decl(name, value) do log.push(["external_entity_decl", name, value]) if decl_handler != null then decl_handler.external_entity_decl(name, value) @@ -486,8 +477,7 @@ class SAXEventLogger ############################################################################ # LexicalHandler - redef fun start_dtd(name: String, public_id: nullable String, - system_id: nullable String) do + redef fun start_dtd(name, public_id, system_id) do log.push(["start_dtd", name, public_id or else "^NULL", system_id or else "^NULL"]) @@ -503,14 +493,14 @@ class SAXEventLogger end end - redef fun start_entity(name: String) do + redef fun start_entity(name) do log.push(["start_entity", name]) if lexical_handler != null then lexical_handler.start_entity(name) end end - redef fun end_entity(name: String) do + redef fun end_entity(name) do log.push(["end_entity", name]) if lexical_handler != null then lexical_handler.end_entity(name) @@ -531,7 +521,7 @@ class SAXEventLogger end end - redef fun comment(str: String) do + redef fun comment(str) do log.push(["comment", str]) if lexical_handler != null then lexical_handler.comment(str) diff --git a/lib/socket/socket.nit b/lib/socket/socket.nit index d553540..a665b41 100644 --- a/lib/socket/socket.nit +++ b/lib/socket/socket.nit @@ -141,7 +141,7 @@ class TCPStream end # If socket.end_reached, nothing will happen - redef fun write(msg: Text) + redef fun write(msg) do if closed then return socket.write(msg.to_s) diff --git a/lib/sqlite3/native_sqlite3.nit b/lib/sqlite3/native_sqlite3.nit index beeb162..dd45211 100644 --- a/lib/sqlite3/native_sqlite3.nit +++ b/lib/sqlite3/native_sqlite3.nit @@ -66,7 +66,7 @@ extern class Sqlite3Code `{int`} new done `{ return SQLITE_DONE; `} # 101 /* sqlite3_step() has finished executing */ fun is_done: Bool `{ return self == SQLITE_DONE; `} - redef fun to_s: String import NativeString.to_s `{ + redef fun to_s import NativeString.to_s `{ #if SQLITE_VERSION_NUMBER >= 3007015 char *err = (char *)sqlite3_errstr(self); #else diff --git a/lib/sqlite3/sqlite3.nit b/lib/sqlite3/sqlite3.nit index 0fe8050..5f90801 100644 --- a/lib/sqlite3/sqlite3.nit +++ b/lib/sqlite3/sqlite3.nit @@ -257,7 +257,7 @@ class StatementIterator redef var item: StatementRow is noinit - redef var is_ok: Bool is noinit + redef var is_ok is noinit # require: `self.statement.is_open` redef fun next diff --git a/lib/standard/bytes.nit b/lib/standard/bytes.nit index b300298..b9b39fd 100644 --- a/lib/standard/bytes.nit +++ b/lib/standard/bytes.nit @@ -31,7 +31,7 @@ class Bytes private var items: NativeString # Number of bytes in the array - redef var length: Int + redef var length # Capacity of the array private var capacity: Int @@ -58,7 +58,7 @@ class Bytes # var b = new Bytes.empty # b.add 101 # assert b[0] == 101 - redef fun [](i: Int): Int do + redef fun [](i) do assert i >= 0 assert i < length return items[i].ascii @@ -67,7 +67,7 @@ class Bytes # var b = new Bytes.with_capacity(1) # b[0] = 101 # assert b.to_s == "e" - redef fun []=(i: Int, v: Int) do + redef fun []=(i, v) do if persisted then regen assert i >= 0 assert i <= length @@ -78,7 +78,7 @@ class Bytes # var b = new Bytes.empty # b.add 101 # assert b.to_s == "e" - redef fun add(c: Int) do + redef fun add(c) do if persisted then regen if length >= capacity then enlarge(length) @@ -90,7 +90,7 @@ class Bytes # var b = new Bytes.empty # b.append([104, 101, 108, 108, 111]) # assert b.to_s == "hello" - redef fun append(arr: Collection[Int]) do + redef fun append(arr) do if arr isa Bytes then append_ns(arr.items, arr.length) else @@ -147,7 +147,7 @@ private class BytesIterator var tgt: NativeString - redef var index: Int + redef var index var max: Int diff --git a/lib/standard/collection/abstract_collection.nit b/lib/standard/collection/abstract_collection.nit index 8b01780..16e4b1e 100644 --- a/lib/standard/collection/abstract_collection.nit +++ b/lib/standard/collection/abstract_collection.nit @@ -317,7 +317,7 @@ private class ContainerIterator[E] redef fun next do is_ok = false - redef var is_ok: Bool = true + redef var is_ok = true var container: Container[E] end @@ -1100,7 +1100,7 @@ end private class CoupleMapIterator[K, V] super MapIterator[K, V] redef fun item do return _iter.item.second - + #redef fun item=(e) do _iter.item.second = e redef fun key do return _iter.item.first diff --git a/lib/standard/collection/array.nit b/lib/standard/collection/array.nit index b3ec382..de66e21 100644 --- a/lib/standard/collection/array.nit +++ b/lib/standard/collection/array.nit @@ -5,7 +5,7 @@ # # This file is free software, which comes along with NIT. This software is # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. You can modify it is you want, provided this header # is kept unaltered, and a notification of the changes is added. # You are allowed to redistribute it and sell it, alone or is a part of @@ -65,8 +65,7 @@ abstract class AbstractArrayRead[E] redef fun last_index_of(item) do return last_index_of_from(item, length-1) - redef fun index_of_from(item, pos) - do + redef fun index_of_from(item, pos) do var i = pos var len = length while i < len do @@ -78,8 +77,7 @@ abstract class AbstractArrayRead[E] return -1 end - redef fun last_index_of_from(item, pos) - do + redef fun last_index_of_from(item, pos) do var i = pos while i >= 0 do if self[i] == item then @@ -242,8 +240,7 @@ abstract class AbstractArray[E] self[0] = item end - redef fun insert(item: E, pos: Int) - do + redef fun insert(item, pos) do enlarge(length + 1) copy_to(pos, length-pos, self, pos + 1) self[pos] = item diff --git a/lib/standard/collection/range.nit b/lib/standard/collection/range.nit index c611ec1..29fa17e 100644 --- a/lib/standard/collection/range.nit +++ b/lib/standard/collection/range.nit @@ -19,7 +19,7 @@ import abstract_collection class Range[E: Discrete] super Collection[E] - redef var first: E + redef var first # Get the last element. var last: E diff --git a/lib/standard/collection/union_find.nit b/lib/standard/collection/union_find.nit index f4c6baa..b44b7f9 100644 --- a/lib/standard/collection/union_find.nit +++ b/lib/standard/collection/union_find.nit @@ -115,8 +115,7 @@ class DisjointSet[E] # s.add(1) # assert s.has(1) # assert not s.has(2) - redef fun has(e) - do + redef fun has(e) do return nodes.has_key(e) end @@ -126,8 +125,7 @@ class DisjointSet[E] # Initially it is in its own disjoint subset # # ENSURE: `has(e)` - redef fun add(e:E) - do + redef fun add(e) do if nodes.has_key(e) then return var ne = new DisjointSetNode nodes[e] = ne diff --git a/lib/standard/file.nit b/lib/standard/file.nit index 5a89d10..3bad3f3 100644 --- a/lib/standard/file.nit +++ b/lib/standard/file.nit @@ -135,7 +135,7 @@ class FileReader end # End of file? - redef var end_reached: Bool = false + redef var end_reached = false # Open the file at `path` for reading. # @@ -299,7 +299,7 @@ class Stdin prepare_buffer(1) end - redef fun poll_in: Bool is extern "file_stdin_poll_in" + redef fun poll_in is extern "file_stdin_poll_in" end # Standard output stream. diff --git a/lib/standard/kernel.nit b/lib/standard/kernel.nit index 85386b4..ffd684a 100644 --- a/lib/standard/kernel.nit +++ b/lib/standard/kernel.nit @@ -5,7 +5,7 @@ # # This file is free software, which comes along with NIT. This software is # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. You can modify it is you want, provided this header # is kept unaltered, and a notification of the changes is added. # You are allowed to redistribute it and sell it, alone or is a part of @@ -128,7 +128,7 @@ interface Comparable type OTHER: Comparable # Is `self` lesser than `other`? - fun <(other: OTHER): Bool is abstract + fun <(other: OTHER): Bool is abstract # not `other` < `self` # Note, the implementation must ensure that: `(x<=y) == (x=(i): Bool is intern - redef fun >(i): Bool is intern + redef fun <=(i) is intern + redef fun <(i) is intern + redef fun >=(i) is intern + redef fun >(i) is intern redef fun +(i) is intern redef fun - is intern @@ -483,9 +483,9 @@ universal Int redef fun is_between(c, d) do - if self < c or d < self then + if self < c or d < self then return false - else + else return true end end @@ -536,7 +536,7 @@ universal Int # count digits while n > 0 do d += 1 - n = n / b # euclidian division / + n = n / b # euclidian division / end return d end diff --git a/lib/standard/ropes.nit b/lib/standard/ropes.nit index 5ac6ee2..902649a 100644 --- a/lib/standard/ropes.nit +++ b/lib/standard/ropes.nit @@ -74,7 +74,7 @@ end private class Concat super RopeString - redef var length: Int is noinit + redef var length is noinit redef fun substrings do return new RopeSubstrings(self) @@ -159,7 +159,6 @@ private class Concat end redef fun copy_to_native(dest, n, src_offset, dest_offset) do - var remlen = n var subs = new RopeSubstrings.from(self, src_offset) var st = src_offset - subs.pos var off = dest_offset @@ -827,7 +826,7 @@ class RopeBufferIter # Maximum position iterable. var maxpos: Int - redef var index: Int + redef var index # Init the iterator from a RopeBuffer. init(t: RopeBuffer) is old_style_init do @@ -877,7 +876,7 @@ class RopeBufferReviter # Current position in `ns`. var pns: Int - redef var index: Int + redef var index # Init the iterator from a RopeBuffer. init(tgt: RopeBuffer) is old_style_init do diff --git a/lib/standard/string.nit b/lib/standard/string.nit index 61af948..60f3af9 100644 --- a/lib/standard/string.nit +++ b/lib/standard/string.nit @@ -898,8 +898,8 @@ abstract class Text # # REQUIRE: `n` must be large enough to contain `len` bytes # - # var ns = new NativeString(8) - # "Text is String".copy_to_native(ns, 8, 2, 0) + # var ns = new NativeString(8) + # "Text is String".copy_to_native(ns, 8, 2, 0) # assert ns.to_s_with_length(8) == "xt is St" # fun copy_to_native(dest: NativeString, n, src_offset, dest_offset: Int) do @@ -945,7 +945,7 @@ abstract class FlatText # copy locally the char* as Nit Strings are immutable. private fun fast_cstring: NativeString is abstract - redef var length: Int = 0 + redef var length = 0 redef fun output do @@ -1194,7 +1194,7 @@ class FlatString # Indes in _items of the last item of the string private var index_to: Int is noinit - redef var chars: SequenceRead[Char] = new FlatStringCharView(self) is lazy + redef var chars = new FlatStringCharView(self) is lazy redef fun [](index) do @@ -1319,8 +1319,7 @@ class FlatString index_to = to end - redef fun to_cstring: NativeString - do + redef fun to_cstring do if real_items != null then return real_items.as(not null) else @@ -1738,8 +1737,7 @@ class FlatBuffer capacity = c end - redef fun to_s: String - do + redef fun to_s do written = true if length == 0 then items = new NativeString(1) return new FlatString.with_infos(items, length, 0, length - 1) diff --git a/lib/string_experimentations/utf8.nit b/lib/string_experimentations/utf8.nit index b2d9372..b3a2450 100644 --- a/lib/string_experimentations/utf8.nit +++ b/lib/string_experimentations/utf8.nit @@ -394,7 +394,7 @@ redef class NativeString return to_s_with_length(len) end - redef fun to_s_with_length(len: Int): FlatString + redef fun to_s_with_length(len) do var real_len = new Container[Int](0) var x = make_index(len, real_len) diff --git a/lib/string_experimentations/utf8_noindex.nit b/lib/string_experimentations/utf8_noindex.nit index 08757aa..8756838 100644 --- a/lib/string_experimentations/utf8_noindex.nit +++ b/lib/string_experimentations/utf8_noindex.nit @@ -271,7 +271,7 @@ redef class FlatString redef type OTHER: FlatString # Length in bytes of the string (e.g. the length of the C string) - redef var bytelen: Int + redef var bytelen # Cache for the last accessed character in the char var cache = new CharCache(-1,-1) @@ -475,7 +475,7 @@ redef class FlatString end # O(n) - redef fun substring(from: Int, count: Int) do + redef fun substring(from, count) do assert count >= 0 if from < 0 then @@ -518,7 +518,7 @@ end redef class FlatBuffer - redef var bytelen: Int + redef var bytelen redef init from(s) do if s isa Concat then @@ -717,7 +717,7 @@ redef class NativeString return to_s_with_length(len) end - redef fun to_s_with_length(len: Int): FlatString + redef fun to_s_with_length(len) do return new FlatString.with_bytelen(self, 0, len - 1, len) end diff --git a/lib/template/template.nit b/lib/template/template.nit index b67df17..fc37617 100644 --- a/lib/template/template.nit +++ b/lib/template/template.nit @@ -200,7 +200,7 @@ class Template end # Do the full rendering and write the final content to a stream - redef fun write_to(stream: Writer) + redef fun write_to(stream) do assert not is_writing is_writing = true diff --git a/src/doc/doc_base.nit b/src/doc/doc_base.nit index 6cd6083..8f0467d 100644 --- a/src/doc/doc_base.nit +++ b/src/doc/doc_base.nit @@ -27,16 +27,26 @@ import model_ext # It is a placeholder to share data between each phase. class DocModel - # `DocPage` composing the documentation. + # `DocPage` composing the documentation associated to their ids. # # This is where `DocPhase` store and access pages to produce documentation. - var pages = new Array[DocPage] + # + # See `add_page`. + var pages: Map[String, DocPage] = new HashMap[String, DocPage] # Nit `Model` from which we extract the documentation. var model: Model is writable # The entry point of the `model`. var mainmodule: MModule is writable + + # Add a `page` to this documentation. + fun add_page(page: DocPage) do + if pages.has_key(page.id) then + print "Warning: multiple page with the same id `{page.id}`" + end + pages[page.id] = page + end end # A documentation page abstraction. @@ -45,6 +55,17 @@ end # the page. class DocPage + # Page uniq id. + # + # The `id` is used as name for the generated file corresponding to the page + # (if any). + # Because multiple pages can be generated in the same directory it should be + # uniq. + # + # The `id` can also be used to establish links between pages (HTML links, + # HTML anchors, vim links, etc.). + var id: String is writable + # Title of this page. var title: String is writable @@ -229,10 +250,30 @@ class PropertyGroup[E: MProperty] end redef class MEntity + # ID used as a unique ID and in file names. + # + # **Must** match the following (POSIX ERE) regular expression: + # + # ~~~POSIX ERE + # ^[A-Za-z_][A-Za-z0-9._-]*$ + # ~~~ + # + # That way, the ID is always a valid URI component and a valid XML name. + fun nitdoc_id: String do return full_name.to_cmangle + # Name displayed in console for debug and tests. fun nitdoc_name: String do return name.html_escape end +redef class MModule + + # Avoid id conflict with group + redef fun nitdoc_id do + if mgroup == null then return super + return "{mgroup.full_name}::{full_name}".to_cmangle + end +end + redef class MClassDef redef fun nitdoc_name do return mclass.nitdoc_name end diff --git a/src/doc/doc_phases/doc_concerns.nit b/src/doc/doc_phases/doc_concerns.nit index d1ada76..cca6346 100644 --- a/src/doc/doc_phases/doc_concerns.nit +++ b/src/doc/doc_phases/doc_concerns.nit @@ -23,7 +23,7 @@ class ConcernsPhase # Populates the given DocModel. redef fun apply do - for page in doc.pages do page.build_concerns(doc) + for page in doc.pages.values do page.build_concerns(doc) end end diff --git a/src/doc/doc_phases/doc_console.nit b/src/doc/doc_phases/doc_console.nit index dbd1d39..f927fd9 100644 --- a/src/doc/doc_phases/doc_console.nit +++ b/src/doc/doc_phases/doc_console.nit @@ -19,6 +19,7 @@ module doc_console import semantize +import doc_extract import doc::console_templates # Nitx handles console I/O. @@ -138,7 +139,7 @@ interface NitxQuery # Pretty prints the results for the console. fun make_results(nitx: Nitx, results: Array[NitxMatch]): DocPage do - var page = new DocPage("Results") + var page = new DocPage("results", "Results") page.root.add_child(new QueryResultArticle(self, results)) return page end @@ -203,7 +204,7 @@ class CommentQuery redef fun perform(nitx, doc) do var name = args.first var res = new Array[NitxMatch] - for mentity in doc.search_mentities(name) do + for mentity in doc.mentities_by_name(name) do res.add new MEntityMatch(self, mentity) end return res @@ -214,7 +215,7 @@ class CommentQuery if len == 1 then var res = results.first.as(MEntityMatch) var mentity = res.mentity - var page = new DocPage("Results") + var page = new DocPage("resultats", "Results") var article = new DefinitionArticle(mentity) article.cs_title = mentity.name article.cs_subtitle = mentity.cs_declaration @@ -317,7 +318,7 @@ class DocQuery redef fun perform(nitx, doc) do var res = new Array[NitxMatch] var name = args.first - for page in doc.pages do + for page in doc.pages.values do if name == "*" then # FIXME dev only res.add new PageMatch(self, page) else if page.title == name then @@ -377,7 +378,7 @@ class CodeQuery return res end # else, lookup the model by name - for mentity in doc.search_mentities(name) do + for mentity in doc.mentities_by_name(name) do if mentity isa MClass then continue if mentity isa MProperty then continue res.add new CodeMatch(self, mentity.cs_location, mentity.cs_source_code) @@ -386,7 +387,7 @@ class CodeQuery end redef fun make_results(nitx, results) do - var page = new DocPage("Code Results") + var page = new DocPage("results", "Code Results") for res in results do page.add new CodeQueryArticle(self, res.as(CodeMatch)) end @@ -435,32 +436,6 @@ end ## exploration -redef class DocModel - - # Lists all MEntities in the model. - private var mentities: Collection[MEntity] is lazy do - var res = new HashSet[MEntity] - res.add_all mprojects - res.add_all mgroups - res.add_all mmodules - res.add_all mclasses - res.add_all mclassdefs - res.add_all mproperties - res.add_all mpropdefs - return res - end - - # Search MEntities that match `name` by their name or namespace. - private fun search_mentities(name: String): Array[MEntity] do - var res = new Array[MEntity] - for mentity in mentities do - if mentity.name != name and mentity.cs_namespace != name then continue - res.add mentity - end - return res - end -end - # Visitor looking for initialized `MType` (new T). # # See `NewQuery`. diff --git a/src/doc/doc_phases/doc_extract.nit b/src/doc/doc_phases/doc_extract.nit index 53adeac..456d545 100644 --- a/src/doc/doc_phases/doc_extract.nit +++ b/src/doc/doc_phases/doc_extract.nit @@ -146,4 +146,78 @@ redef class DocModel end end end + + # Lists all MEntities in the model. + # + # FIXME invalidate cache if `self` is modified. + var mentities: Collection[MEntity] is lazy do + var res = new HashSet[MEntity] + res.add_all mprojects + res.add_all mgroups + res.add_all mmodules + res.add_all mclasses + res.add_all mclassdefs + res.add_all mproperties + res.add_all mpropdefs + return res + end + + # Searches MEntities that match `name`. + fun mentities_by_name(name: String): Array[MEntity] do + var res = new Array[MEntity] + for mentity in mentities do + if mentity.name != name then continue + res.add mentity + end + return res + end + + # Looks up a MEntity by its `namespace`. + # + # Usefull when `mentities_by_name` by return conflicts. + # + # Path can be the shortest possible to disambiguise like `Class::property`. + # In case of larger conflicts, a more complex namespace can be given like + # `project::module::Class::prop`. + fun mentities_by_namespace(namespace: String): Array[MEntity] do + var res = new Array[MEntity] + for mentity in mentities do + mentity.mentities_by_namespace(namespace, res) + end + return res + end +end + +redef class MEntity + # Looks up a MEntity by its `namespace` from `self`. + private fun mentities_by_namespace(namespace: String, res: Array[MEntity]) do end + + private fun lookup_in(mentities: Collection[MEntity], namespace: String, res: Array[MEntity]) do + var parts = namespace.split_once_on("::") + var name = parts.shift + for mentity in mentities do + if mentity.name != name then continue + if parts.is_empty then + res.add mentity + else + mentity.mentities_by_namespace(parts.first, res) + end + end + end +end + +redef class MProject + redef fun mentities_by_namespace(namespace, res) do lookup_in(mgroups, namespace, res) +end + +redef class MGroup + redef fun mentities_by_namespace(namespace, res) do lookup_in(mmodules, namespace, res) +end + +redef class MModule + redef fun mentities_by_namespace(namespace, res) do lookup_in(mclassdefs, namespace, res) +end + +redef class MClassDef + redef fun mentities_by_namespace(namespace, res) do lookup_in(mpropdefs, namespace, res) end diff --git a/src/doc/doc_phases/doc_graphs.nit b/src/doc/doc_phases/doc_graphs.nit index 07b7c99..1339d09 100644 --- a/src/doc/doc_phases/doc_graphs.nit +++ b/src/doc/doc_phases/doc_graphs.nit @@ -36,7 +36,7 @@ class GraphPhase redef fun apply do if ctx.opt_nodot.value then return - for page in doc.pages do + for page in doc.pages.values do var article = page.build_graph(self, doc) if article == null then continue # FIXME avoid diff diff --git a/src/doc/doc_phases/doc_hierarchies.nit b/src/doc/doc_phases/doc_hierarchies.nit index 5bfbfb1..eecc95b 100644 --- a/src/doc/doc_phases/doc_hierarchies.nit +++ b/src/doc/doc_phases/doc_hierarchies.nit @@ -26,7 +26,7 @@ class InheritanceListsPhase var name_sorter = new MEntityNameSorter redef fun apply do - for page in doc.pages do + for page in doc.pages.values do if page isa MEntityPage then page.build_inh_list(self, doc) end end diff --git a/src/doc/doc_phases/doc_html.nit b/src/doc/doc_phases/doc_html.nit index 156a650..0c843bb 100644 --- a/src/doc/doc_phases/doc_html.nit +++ b/src/doc/doc_phases/doc_html.nit @@ -104,7 +104,7 @@ class RenderHTMLPhase redef fun apply do init_output_dir - for page in doc.pages do + for page in doc.pages.values do page.render(self, doc).write_to_file("{ctx.output_dir.to_s}/{page.html_url}") end end @@ -187,7 +187,7 @@ redef class DocPage # all properties below are roughly copied from `doc_pages` # Build page title string - fun init_title(v: RenderHTMLPhase, doc: DocModel) is abstract + fun init_title(v: RenderHTMLPhase, doc: DocModel) do end # Build top menu template if any. fun init_topmenu(v: RenderHTMLPhase, doc: DocModel) do diff --git a/src/doc/doc_phases/doc_intros_redefs.nit b/src/doc/doc_phases/doc_intros_redefs.nit index 54f7c18..5ed6f78 100644 --- a/src/doc/doc_phases/doc_intros_redefs.nit +++ b/src/doc/doc_phases/doc_intros_redefs.nit @@ -24,7 +24,7 @@ class IntroRedefListPhase super DocPhase redef fun apply do - for page in doc.pages do + for page in doc.pages.values do if not page isa MEntityPage then continue page.root.build_intro_redef_list(self, doc, page) end diff --git a/src/doc/doc_phases/doc_lin.nit b/src/doc/doc_phases/doc_lin.nit index eda76ba..c36756c 100644 --- a/src/doc/doc_phases/doc_lin.nit +++ b/src/doc/doc_phases/doc_lin.nit @@ -25,7 +25,7 @@ class LinListPhase private var lin_sorter = new MEntityNameSorter redef fun apply do - for page in doc.pages do page.apply_linearization(self, doc) + for page in doc.pages.values do page.apply_linearization(self, doc) end end diff --git a/src/doc/doc_phases/doc_pages.nit b/src/doc/doc_phases/doc_pages.nit index e468cb6..3f83001 100644 --- a/src/doc/doc_phases/doc_pages.nit +++ b/src/doc/doc_phases/doc_pages.nit @@ -23,19 +23,19 @@ class MakePagePhase # Instanciates documentation pages for the given DocModel. redef fun apply do - doc.pages.add new OverviewPage("Overview") - doc.pages.add new SearchPage("Index") + doc.add_page new OverviewPage("overview", "Overview") + doc.add_page new SearchPage("search", "Index") for mgroup in doc.mgroups do - doc.pages.add new MGroupPage(mgroup.nitdoc_name, mgroup) + doc.add_page new MGroupPage(mgroup) end for mmodule in doc.mmodules do - doc.pages.add new MModulePage(mmodule.nitdoc_name, mmodule) + doc.add_page new MModulePage(mmodule) end for mclass in doc.mclasses do - doc.pages.add new MClassPage(mclass.nitdoc_name, mclass) + doc.add_page new MClassPage(mclass) end for mproperty in doc.mproperties do - doc.pages.add new MPropertyPage(mproperty.nitdoc_name, mproperty) + doc.add_page new MPropertyPage(mproperty) end end end @@ -52,6 +52,7 @@ end # A DocPage documenting a MEntity. class MEntityPage + autoinit mentity super DocPage # Type of MEntity documented by this page. @@ -59,6 +60,9 @@ class MEntityPage # MEntity documented by this page. var mentity: MENTITY + + redef var id is lazy do return mentity.nitdoc_id + redef var title is lazy do return mentity.nitdoc_name end # A documentation page about a MGroup. diff --git a/src/doc/doc_phases/doc_poset.nit b/src/doc/doc_phases/doc_poset.nit index fd38e0f..0c610d4 100644 --- a/src/doc/doc_phases/doc_poset.nit +++ b/src/doc/doc_phases/doc_poset.nit @@ -23,7 +23,7 @@ class POSetPhase # Populates the given DocModel. redef fun apply do - for page in doc.pages do + for page in doc.pages.values do if page isa MEntityPage then page.build_poset(self, doc) end end diff --git a/src/doc/doc_phases/doc_structure.nit b/src/doc/doc_phases/doc_structure.nit index 507a0a4..7491e4b 100644 --- a/src/doc/doc_phases/doc_structure.nit +++ b/src/doc/doc_phases/doc_structure.nit @@ -33,7 +33,7 @@ class StructurePhase # Populates the given DocModel. redef fun apply do - for page in doc.pages do page.apply_structure(self, doc) + for page in doc.pages.values do page.apply_structure(self, doc) end end diff --git a/src/doc/html_templates/html_model.nit b/src/doc/html_templates/html_model.nit index cd6974c..bc8ccbe 100644 --- a/src/doc/html_templates/html_model.nit +++ b/src/doc/html_templates/html_model.nit @@ -22,17 +22,6 @@ import html::bootstrap import ordered_tree redef class MEntity - # ID used as a HTML unique ID and in file names. - # - # **Must** match the following (POSIX ERE) regular expression: - # - # ~~~POSIX ERE - # ^[A-Za-z_][A-Za-z0-9._-]*$ - # ~~~ - # - # That way, the ID is always a valid URI component and a valid XML name. - fun nitdoc_id: String is abstract - # URL of this entity’s Nitdoc page. fun nitdoc_url: String is abstract diff --git a/src/frontend/check_annotation.nit b/src/frontend/check_annotation.nit index 6d9bb60..eb05a14 100644 --- a/src/frontend/check_annotation.nit +++ b/src/frontend/check_annotation.nit @@ -84,6 +84,7 @@ readonly writable autoinit noautoinit +lateinit nosuper old_style_init abstract diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index 5242cdc..f1cce80 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -206,9 +206,9 @@ redef class ModelBuilder var mreadpropdef = npropdef.mreadpropdef if mreadpropdef == null or mreadpropdef.msignature == null then return # Skip broken attribute if npropdef.noinit then continue # Skip noinit attribute - var atautoinit = npropdef.get_single_annotation("autoinit", self) - if atautoinit != null then - # For autoinit attributes, call the reader to force + var atlateinit = npropdef.get_single_annotation("lateinit", self) + if atlateinit != null then + # For lateinit attributes, call the reader to force # the lazy initialization of the attribute. initializers.add(mreadpropdef.mproperty) mreadpropdef.mproperty.is_autoinit = true @@ -660,6 +660,8 @@ redef class APropdef return true end + # Checks for useless type in redef signatures. + private fun check_repeated_types(modelbuilder: ModelBuilder) do end end redef class ASignature @@ -1055,6 +1057,28 @@ redef class AMethPropdef var nt = nsig.n_type if nt != null then modelbuilder.check_visibility(nt, nt.mtype.as(not null), mpropdef) end + check_repeated_types(modelbuilder) + end + + # For parameters, type is always useless in a redef. + # For return type, type is useless if not covariant with introduction. + redef fun check_repeated_types(modelbuilder) do + if mpropdef.is_intro or n_signature == null then return + # check params + for param in n_signature.n_params do + if param.n_type != null then + modelbuilder.advice(param.n_type, "useless-signature", "Warning: useless type repetition on parameter `{param.n_id.text}` for redefined method `{mpropdef.name}`") + end + end + # get intro + var intro = mpropdef.mproperty.intro + var n_intro = modelbuilder.mpropdef2npropdef.get_or_null(intro) + if n_intro == null or not n_intro isa AMethPropdef then return + # check return type + var ret_type = n_signature.ret_type + if ret_type != null and ret_type == n_intro.n_signature.ret_type then + modelbuilder.advice(n_signature.n_type, "useless-signature", "Warning: useless return type repetition for redefined method `{mpropdef.name}`") + end end end @@ -1191,17 +1215,17 @@ redef class AAttrPropdef end var atlazy = self.get_single_annotation("lazy", modelbuilder) - var atautoinit = self.get_single_annotation("autoinit", modelbuilder) - if atlazy != null or atautoinit != null then - if atlazy != null and atautoinit != null then - modelbuilder.error(atlazy, "Error: `lazy` incompatible with `autoinit`.") + var atlateinit = self.get_single_annotation("lateinit", modelbuilder) + if atlazy != null or atlateinit != null then + if atlazy != null and atlateinit != null then + modelbuilder.error(atlazy, "Error: `lazy` incompatible with `lateinit`.") return end if not has_value then if atlazy != null then modelbuilder.error(atlazy, "Error: `lazy` attributes need a value.") - else if atautoinit != null then - modelbuilder.error(atautoinit, "Error: `autoinit` attributes need a value.") + else if atlateinit != null then + modelbuilder.error(atlateinit, "Error: `lateinit` attributes need a value.") end has_value = true return @@ -1350,6 +1374,7 @@ redef class AAttrPropdef if mlazypropdef != null then mlazypropdef.static_mtype = modelbuilder.model.get_mclasses_by_name("Bool").first.mclass_type end + check_repeated_types(modelbuilder) end redef fun check_signature(modelbuilder) @@ -1454,6 +1479,25 @@ redef class AAttrPropdef end end end + + # Type is useless if the attribute type is the same thant the intro. + redef fun check_repeated_types(modelbuilder) do + if mreadpropdef.is_intro or n_type == null then return + # get intro + var intro = mreadpropdef.mproperty.intro + var n_intro = modelbuilder.mpropdef2npropdef.get_or_null(intro) + if n_intro == null then return + # get intro type + var ntype = null + if n_intro isa AMethPropdef then + ntype = n_intro.n_signature.ret_type + else if n_intro isa AAttrPropdef and n_intro.n_type != null then + ntype = n_intro.n_type.mtype + end + # check + if ntype ==null or ntype != n_type.mtype then return + modelbuilder.advice(n_type, "useless-signature", "Warning: useless type repetition on redefined attribute `{mpropdef.name}`") + end end redef class ATypePropdef diff --git a/src/nitpick.nit b/src/nitpick.nit index 44cab72..4d00945 100644 --- a/src/nitpick.nit +++ b/src/nitpick.nit @@ -49,7 +49,7 @@ var model = new Model # A model builder to parse files var modelbuilder = new ModelBuilder(model, toolcontext) -# Here we load an process all modules passed on the command line +# Here we load and process all modules passed on the command line var mmodules = modelbuilder.parse_full(arguments) toolcontext.mmodules_to_check.add_all mmodules diff --git a/tests/base_init_autoinit2.nit b/tests/base_init_autoinit2.nit index 5930588..081b84b 100644 --- a/tests/base_init_autoinit2.nit +++ b/tests/base_init_autoinit2.nit @@ -19,8 +19,8 @@ class A var b: Object is noautoinit #alt1#var b2: Object = get(-4) is noautoinit var c: Object is noautoinit - var d: Object = get(2) is autoinit - #alt2#var d2: Object = get(-2) is autoinit, lazy + var d: Object = get(2) is lateinit + #alt2#var d2: Object = get(-2) is lateinit, lazy var e: Object = get(1) fun setc(v: Object) is autoinit do self.c = get(v) init do diff --git a/tests/nitpick.args b/tests/nitpick.args new file mode 100644 index 0000000..3ae7a2a --- /dev/null +++ b/tests/nitpick.args @@ -0,0 +1 @@ +--no-color -W test_advice_repeated_types.nit diff --git a/tests/sav/base_init_autoinit2_alt2.res b/tests/sav/base_init_autoinit2_alt2.res index 91e3496..db23606 100644 --- a/tests/sav/base_init_autoinit2_alt2.res +++ b/tests/sav/base_init_autoinit2_alt2.res @@ -1 +1 @@ -alt/base_init_autoinit2_alt2.nit:23,40--43: Error: `lazy` incompatible with `autoinit`. +alt/base_init_autoinit2_alt2.nit:23,40--43: Error: `lazy` incompatible with `lateinit`. diff --git a/tests/sav/nitpick_args1.res b/tests/sav/nitpick_args1.res new file mode 100644 index 0000000..38f9166 --- /dev/null +++ b/tests/sav/nitpick_args1.res @@ -0,0 +1,12 @@ +../lib/standard/bytes.nit:51,7--19: Documentation warning: Undocumented property `with_capacity` +../lib/standard/bytes.nit:164,6--13: Documentation warning: Undocumented property `to_bytes` +../lib/standard/stream.nit:425,6--17: Documentation warning: Undocumented property `buffer_reset` +../lib/standard/file.nit:444,6--19: Documentation warning: Undocumented property `read_all_bytes` +test_advice_repeated_types.nit:36,15--20: Warning: useless type repetition on redefined attribute `_a` +test_advice_repeated_types.nit:37,18--20: Warning: useless type repetition on parameter `b1` for redefined method `b` +test_advice_repeated_types.nit:38,18--20: Warning: useless type repetition on parameter `c1` for redefined method `c` +test_advice_repeated_types.nit:38,27--29: Warning: useless type repetition on parameter `c2` for redefined method `c` +test_advice_repeated_types.nit:39,15--20: Warning: useless return type repetition for redefined method `d` +test_advice_repeated_types.nit:40,18--20: Warning: useless type repetition on parameter `e1` for redefined method `e` +test_advice_repeated_types.nit:40,24--29: Warning: useless return type repetition for redefined method `e` +test_advice_repeated_types.nit:49,18--20: Warning: useless type repetition on parameter `e1` for redefined method `e` diff --git a/tests/sav/test_new_native_alt1.res b/tests/sav/test_new_native_alt1.res index 43e3636..209563a 100644 --- a/tests/sav/test_new_native_alt1.res +++ b/tests/sav/test_new_native_alt1.res @@ -1,4 +1,4 @@ -Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:960) +Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:957) NativeString N Nit diff --git a/tests/test_advice_repeated_types.nit b/tests/test_advice_repeated_types.nit new file mode 100644 index 0000000..21f1a04 --- /dev/null +++ b/tests/test_advice_repeated_types.nit @@ -0,0 +1,56 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class A + var a: Object + fun b(b1: Int) is abstract + fun c(c1: Int, c2: Int) is abstract + fun d: Object is abstract + fun e(e1: Int): Object is abstract +end + +class B + super A + + redef var a + redef fun b(b1) do end + redef fun c(c1, c2) do end + redef fun d do return "" + redef fun e(e1) do return "" +end + +class C + super A + + redef var a: Object + redef fun b(b1: Int) do end + redef fun c(c1: Int, c2: Int) do end + redef fun d: Object do return "" + redef fun e(e1: Int): Object do return "" +end + +class D + super A + + redef fun b(b1) do end + redef fun c(c1, c2) do end + redef fun d: Int do return 1 + redef fun e(e1: Int): Numeric do return 1 +end + +class E + super A + + redef var d: Int = 1 +end